diff --git a/ee/app/models/security/orchestration_policy_configuration.rb b/ee/app/models/security/orchestration_policy_configuration.rb
index 3e9038e77e17ad5e54d24dc8fc7737a265aa4219..ecb9666a30bda61ba97f7751561c6c68a164223e 100644
--- a/ee/app/models/security/orchestration_policy_configuration.rb
+++ b/ee/app/models/security/orchestration_policy_configuration.rb
@@ -46,6 +46,7 @@ class OrchestrationPolicyConfiguration < ApplicationRecord
     scope :for_namespace, ->(namespace_id) { where(namespace_id: namespace_id) }
     scope :with_project_and_namespace, -> { includes(:project, :namespace) }
     scope :for_management_project, ->(management_project_id) { where(security_policy_management_project_id: management_project_id) }
+    scope :with_security_policies, -> { includes(:security_policies) }
     scope :with_outdated_configuration, -> do
       joins(:security_policy_management_project)
         .where(arel_table[:configured_at].lt(Project.arel_table[:last_repository_updated_at]).or(arel_table[:configured_at].eq(nil)))
diff --git a/ee/app/models/security/policy.rb b/ee/app/models/security/policy.rb
index 2965fdb14c972f90d473d89209a62ad75ab9b871..c1943dc8dcc01eaa996901a09d9d8194997c35ef 100644
--- a/ee/app/models/security/policy.rb
+++ b/ee/app/models/security/policy.rb
@@ -161,6 +161,12 @@ def scope_applicable?(project)
       policy_scope_checker.security_policy_applicable?(self)
     end
 
+    def scope_has_framework?(compliance_framework_id)
+      scope
+        .deep_symbolize_keys[:compliance_frameworks].to_a
+        .any? { |framework| framework[:id] == compliance_framework_id }
+    end
+
     def delete_approval_policy_rules
       delete_approval_rules
       delete_policy_violations
diff --git a/ee/app/services/security/security_orchestration_policies/sync_policy_event_service.rb b/ee/app/services/security/security_orchestration_policies/sync_policy_event_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7d3bc29cec6ee5bcfdd3a480a13ac8ec8d48c99d
--- /dev/null
+++ b/ee/app/services/security/security_orchestration_policies/sync_policy_event_service.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Security
+  module SecurityOrchestrationPolicies
+    class SyncPolicyEventService < BaseProjectPolicyService
+      def initialize(project:, security_policy:, event:)
+        super(project: project, security_policy: security_policy)
+        @event = event
+      end
+
+      def execute
+        case event
+        when Projects::ComplianceFrameworkChangedEvent
+          sync_policy_for_compliance_framework(event)
+        end
+      end
+
+      private
+
+      def sync_policy_for_compliance_framework(event)
+        return unless security_policy.scope_has_framework?(event.data[:compliance_framework_id])
+
+        if event.data[:event_type] == Projects::ComplianceFrameworkChangedEvent::EVENT_TYPES[:added]
+          link_policy
+        else
+          unlink_policy
+        end
+      end
+
+      attr_reader :event
+    end
+  end
+end
diff --git a/ee/app/workers/security/refresh_compliance_framework_security_policies_worker.rb b/ee/app/workers/security/refresh_compliance_framework_security_policies_worker.rb
index 46c65c3a1a149c966aee0e55d35a6d7a5b05666d..9353e45d574aabe9fec6f837ef1b5ff32dc0d646 100644
--- a/ee/app/workers/security/refresh_compliance_framework_security_policies_worker.rb
+++ b/ee/app/workers/security/refresh_compliance_framework_security_policies_worker.rb
@@ -18,9 +18,20 @@ def handle_event(event)
       policy_configuration_ids = project.all_security_orchestration_policy_configuration_ids
       return unless policy_configuration_ids.any?
 
-      framework.security_orchestration_policy_configurations.id_in(policy_configuration_ids).find_each do |config|
-        Security::ProcessScanResultPolicyWorker.perform_async(project.id, config.id)
-      end
+      framework
+        .security_orchestration_policy_configurations
+        .with_security_policies.id_in(policy_configuration_ids)
+        .find_each do |config|
+          Security::ProcessScanResultPolicyWorker.perform_async(project.id, config.id)
+
+          config.security_policies.undeleted.find_each do |security_policy|
+            Security::SecurityOrchestrationPolicies::SyncPolicyEventService.new(
+              project: project,
+              security_policy: security_policy,
+              event: event
+            ).execute
+          end
+        end
     end
   end
 end
diff --git a/ee/spec/models/security/policy_spec.rb b/ee/spec/models/security/policy_spec.rb
index ee8080e77b47df4640966c73c0bacf2fa5d3d775..d88c3e3158dc822e186efed71e07094551174889 100644
--- a/ee/spec/models/security/policy_spec.rb
+++ b/ee/spec/models/security/policy_spec.rb
@@ -409,6 +409,30 @@
     end
   end
 
+  describe '#scope_has_framework?' do
+    let(:framework) { create(:compliance_framework) }
+    let(:policy_scope) { {} }
+    let(:security_policy) { create(:security_policy, scope: policy_scope) }
+
+    subject(:scope_has_framework?) { security_policy.scope_has_framework?(framework.id) }
+
+    context 'when scope is empty' do
+      it { is_expected.to be_falsey }
+    end
+
+    context 'when scope contains framework_id' do
+      let(:policy_scope) { { compliance_frameworks: [{ id: framework.id }] } }
+
+      it { is_expected.to be_truthy }
+    end
+
+    context 'when scope has a non existing framework_id' do
+      let(:policy_scope) { { compliance_frameworks: [{ id: non_existing_record_id }] } }
+
+      it { is_expected.to be_falsey }
+    end
+  end
+
   describe '#delete_approval_policy_rules' do
     let_it_be(:policy) { create(:security_policy, :require_approval) }
     let_it_be(:other_policy) { create(:security_policy, :require_approval) }
diff --git a/ee/spec/services/security/security_orchestration_policies/sync_policy_event_service_spec.rb b/ee/spec/services/security/security_orchestration_policies/sync_policy_event_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..49d4c8a55d753b5a2cfedbcd9eff46208a0816a9
--- /dev/null
+++ b/ee/spec/services/security/security_orchestration_policies/sync_policy_event_service_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Security::SecurityOrchestrationPolicies::SyncPolicyEventService, feature_category: :security_policy_management do
+  let_it_be(:project) { create(:project) }
+  let_it_be(:compliance_framework) { create(:compliance_framework) }
+
+  let(:policy_scope) { { compliance_frameworks: [{ id: compliance_framework.id }] } }
+  let(:security_policy) do
+    create(:security_policy, scope: policy_scope)
+  end
+
+  before do
+    create(:compliance_framework_project_setting,
+      project: project,
+      compliance_management_framework: compliance_framework
+    )
+  end
+
+  subject(:execute) { described_class.new(project: project, security_policy: security_policy, event: event).execute }
+
+  describe '#execute' do
+    context 'when event is ComplianceFrameworkChangedEvent' do
+      let(:event) do
+        Projects::ComplianceFrameworkChangedEvent.new(data: {
+          project_id: project.id,
+          compliance_framework_id: compliance_framework.id,
+          event_type: event_type
+        })
+      end
+
+      shared_examples 'when policy scope does not match compliance_framework' do
+        context 'when policy scope does not have compliance_framework' do
+          let(:policy_scope) { {} }
+
+          it 'does nothing' do
+            expect { execute }.not_to change { Security::PolicyProjectLink.count }
+          end
+        end
+
+        context 'when policy scope has a different compliance framework' do
+          let_it_be(:other_compliance_framework) { create(:compliance_framework) }
+          let(:policy_scope) { { compliance_frameworks: [{ id: other_compliance_framework.id }] } }
+
+          it 'does nothing' do
+            expect { execute }.not_to change { Security::PolicyProjectLink.count }
+          end
+        end
+      end
+
+      context 'when framework is added' do
+        let(:event_type) { Projects::ComplianceFrameworkChangedEvent::EVENT_TYPES[:added] }
+
+        it 'links policy to project' do
+          expect { execute }.to change { Security::PolicyProjectLink.count }.by(1)
+
+          expect(project.security_policies).to contain_exactly(security_policy)
+        end
+
+        it_behaves_like 'when policy scope does not match compliance_framework'
+      end
+
+      context 'when framework is removed' do
+        let(:event_type) { Projects::ComplianceFrameworkChangedEvent::EVENT_TYPES[:removed] }
+
+        context 'when policy is linked to the project' do
+          before do
+            create(:security_policy_project_link, project: project, security_policy: security_policy)
+          end
+
+          it 'unlinks policy from project' do
+            expect { execute }.to change { Security::PolicyProjectLink.count }.by(-1)
+
+            expect(project.reload.security_policies).to be_empty
+          end
+        end
+
+        context 'when policy is not linked to the project' do
+          it 'does nothing' do
+            expect { execute }.not_to change { Security::PolicyProjectLink.count }
+          end
+        end
+
+        it_behaves_like 'when policy scope does not match compliance_framework'
+      end
+    end
+  end
+end
diff --git a/ee/spec/workers/security/refresh_compliance_framework_security_policies_worker_spec.rb b/ee/spec/workers/security/refresh_compliance_framework_security_policies_worker_spec.rb
index c8d9b57714d313b76374db0e3714c176b0200eae..fe1825741b053c7c2f616cb6e8da5eeba5904701 100644
--- a/ee/spec/workers/security/refresh_compliance_framework_security_policies_worker_spec.rb
+++ b/ee/spec/workers/security/refresh_compliance_framework_security_policies_worker_spec.rb
@@ -65,4 +65,62 @@
 
     consume_event(subscriber: described_class, event: compliance_framework_changed_event)
   end
+
+  context 'with security_policies' do
+    let_it_be(:security_policy) do
+      create(:security_policy,
+        security_orchestration_policy_configuration: policy_configuration,
+        scope: { compliance_frameworks: [{ id: compliance_framework.id }] }
+      )
+    end
+
+    let_it_be(:deleted_security_policy) do
+      create(:security_policy, :deleted,
+        security_orchestration_policy_configuration: policy_configuration,
+        scope: { compliance_frameworks: [{ id: compliance_framework.id }] }
+      )
+    end
+
+    let_it_be(:project_security_policy) do
+      create(:security_policy,
+        security_orchestration_policy_configuration: project_policy_configuration,
+        scope: { compliance_frameworks: [{ id: compliance_framework.id }] }
+      )
+    end
+
+    let_it_be(:other_security_policy) do
+      create(:security_policy,
+        security_orchestration_policy_configuration: other_policy_configuration,
+        scope: { compliance_frameworks: [{ id: compliance_framework.id }] }
+      )
+    end
+
+    before do
+      create(:compliance_framework_project_setting,
+        project: project,
+        compliance_management_framework: compliance_framework
+      )
+    end
+
+    it 'invokes Security::SecurityOrchestrationPolicies::SyncPolicyEventService for undeleted policies' do
+      expect_next_instance_of(
+        Security::SecurityOrchestrationPolicies::SyncPolicyEventService,
+        project: project,
+        security_policy: security_policy,
+        event: an_instance_of(::Projects::ComplianceFrameworkChangedEvent)
+      ) do |instance|
+        expect(instance).to receive(:execute)
+      end
+      expect_next_instance_of(
+        Security::SecurityOrchestrationPolicies::SyncPolicyEventService,
+        project: project,
+        security_policy: project_security_policy,
+        event: an_instance_of(::Projects::ComplianceFrameworkChangedEvent)
+      ) do |instance|
+        expect(instance).to receive(:execute)
+      end
+
+      consume_event(subscriber: described_class, event: compliance_framework_changed_event)
+    end
+  end
 end