diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index c81a879ad1a0c8db474eeb139a779dd45dcd15a6..8c99d0f685683230a57dbaec5bc126733a28ee52 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -73,6 +73,7 @@ def proceed_to_transfer
         end
       end
 
+      transfer_labels if Feature.enabled?(:group_labels_transfer)
       remove_paid_features_for_projects(old_root_ancestor_id)
       post_update_hooks(@updated_project_ids, old_root_ancestor_id)
       propagate_integrations
@@ -81,6 +82,14 @@ def proceed_to_transfer
       true
     end
 
+    def transfer_labels
+      @group.all_projects.each_batch(of: 10) do |projects|
+        projects.each do |project|
+          Labels::TransferService.new(current_user, @group, project).execute
+        end
+      end
+    end
+
     # Overridden in EE
     def post_update_hooks(updated_project_ids, old_root_ancestor_id)
       refresh_project_authorizations
diff --git a/config/feature_flags/gitlab_com_derisk/group_labels_transfer.yml b/config/feature_flags/gitlab_com_derisk/group_labels_transfer.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d569c5249633a1c8040bf5cdedf5e98369522cc0
--- /dev/null
+++ b/config/feature_flags/gitlab_com_derisk/group_labels_transfer.yml
@@ -0,0 +1,9 @@
+---
+name: group_labels_transfer
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/354890
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146292
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/443874
+milestone: '16.10'
+group: group::project management
+type: gitlab_com_derisk
+default_enabled: false
diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb
index 8a866b632bd67eaa17cfa4baaa35be6a8cea4a32..8f18013eaf8185214a730c080c29a8995c5732f0 100644
--- a/spec/services/groups/transfer_service_spec.rb
+++ b/spec/services/groups/transfer_service_spec.rb
@@ -141,6 +141,39 @@
     end
   end
 
+  context 'transferring labels' do
+    let(:new_parent_group) { create(:group, :private) }
+    let(:parent_group) { create(:group) }
+    let(:group) { create(:group, parent: parent_group) }
+    let(:project) { create(:project, group: group) }
+
+    before do
+      group.add_owner(user)
+      parent_group.add_owner(user)
+      new_parent_group.add_owner(user)
+    end
+
+    context 'when the feature flag "group_labels_transfer" is disabled' do
+      before do
+        stub_feature_flags(group_labels_transfer: false)
+      end
+
+      it 'does not use Labels::TransferService' do
+        expect(Labels::TransferService).not_to receive(:new)
+
+        transfer_service.execute(new_parent_group)
+      end
+    end
+
+    it 'delegates transfer to Labels::TransferService' do
+      expect_next_instance_of(Labels::TransferService, user, project.group, project) do |labels_transfer_service|
+        expect(labels_transfer_service).to receive(:execute).once.and_call_original
+      end
+
+      transfer_service.execute(new_parent_group)
+    end
+  end
+
   describe '#execute' do
     context 'when transforming a group into a root group' do
       let_it_be_with_reload(:group) { create(:group, :public, :nested) }