diff --git a/app/assets/javascripts/graphql_shared/constants.js b/app/assets/javascripts/graphql_shared/constants.js
index 8269a7790a54ea6f8226000336569745040bbc00..7f2c41d9aaf94c1818856a6699a67eeff52a7747 100644
--- a/app/assets/javascripts/graphql_shared/constants.js
+++ b/app/assets/javascripts/graphql_shared/constants.js
@@ -29,3 +29,4 @@ export const TYPENAME_WORK_ITEM = 'WorkItem';
 export const TYPENAME_ORGANIZATION = 'Organization';
 export const TYPE_USERS_SAVED_REPLY = 'Users::SavedReply';
 export const TYPE_WORKSPACE = 'RemoteDevelopment::Workspace';
+export const TYPE_COMPLIANCE_FRAMEWORK = 'ComplianceManagement::Framework';
diff --git a/ee/app/assets/javascripts/security_orchestration/components/group_projects_dropdown.vue b/ee/app/assets/javascripts/security_orchestration/components/group_projects_dropdown.vue
index e51f38294636af603eada0f9b1bfe11921d2cb70..5a2ea77186ab70c8dec1b116110e4dcff8ec6dee 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/group_projects_dropdown.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/group_projects_dropdown.vue
@@ -2,7 +2,10 @@
 import { GlCollapsibleListbox } from '@gitlab/ui';
 import { debounce } from 'lodash';
 import produce from 'immer';
-import { n__, __ } from '~/locale';
+import { __ } from '~/locale';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { TYPENAME_PROJECT } from '~/graphql_shared/constants';
+import { renderMultiSelectText } from 'ee/security_orchestration/components/policy_editor/utils';
 import getGroupProjects from 'ee/security_orchestration/graphql/queries/get_group_projects.query.graphql';
 import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
 
@@ -51,6 +54,18 @@ export default {
       required: false,
       default: () => [],
     },
+    /**
+     * selected ids passed as short format
+     * [21,34,45] as number
+     * needs to be converted to full graphql id
+     * if false, selectedProjectsIds needs to be
+     * an array of full graphQl ids
+     */
+    useShortIdFormat: {
+      type: Boolean,
+      required: false,
+      default: true,
+    },
   },
   data() {
     return {
@@ -60,18 +75,34 @@ export default {
     };
   },
   computed: {
-    dropdownPlaceholder() {
-      if (this.selectedProjectsIds.length === this.projects.length && !this.loading) {
-        return __('All projects selected');
+    formattedSelectedProjectsIds() {
+      if (this.useShortIdFormat) {
+        return (
+          this.selectedProjectsIds?.map((id) => convertToGraphQLId(TYPENAME_PROJECT, id)) || []
+        );
       }
-      if (this.selectedProjectsIds.length) {
-        return n__('%d project selected', '%d projects selected', this.selectedProjectsIds.length);
-      }
-      return __('Select projects');
+
+      return this.selectedProjectsIds || [];
+    },
+    existingFormattedSelectedProjectsIds() {
+      return this.formattedSelectedProjectsIds.filter((id) => this.projectsIds.includes(id));
+    },
+    dropdownPlaceholder() {
+      return renderMultiSelectText(
+        this.formattedSelectedProjectsIds,
+        this.projectItems,
+        __('projects'),
+      );
     },
     loading() {
       return this.$apollo.queries.projects.loading;
     },
+    projectItems() {
+      return this.projects?.reduce((acc, { id, name }) => {
+        acc[id] = name;
+        return acc;
+      }, {});
+    },
     projectListBoxItems() {
       return this.projects.map(({ id, name }) => ({ text: name, value: id }));
     },
@@ -110,7 +141,9 @@ export default {
       this.searchTerm = searchTerm.trim();
     },
     selectProjects(ids) {
-      this.$emit('select', ids);
+      const payload = this.useShortIdFormat ? ids.map((id) => getIdFromGraphQLId(id)) : ids;
+
+      this.$emit('select', payload);
     },
   },
 };
@@ -128,7 +161,7 @@ export default {
     :infinite-scroll="projectsPageInfo.hasNextPage"
     :infinite-scroll-loading="loading"
     :searching="loading"
-    :selected="selectedProjectsIds"
+    :selected="existingFormattedSelectedProjectsIds"
     :placement="placement"
     :items="projectListBoxItems"
     :reset-button-label="$options.i18n.clearAllLabel"
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/constants.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/constants.js
index 4dc6e7b9a92e5e43b567a251f531de5acefabb1e..8fbabae1f0fb1c3095bc0615d85968cea747b1d9 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/constants.js
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/constants.js
@@ -176,3 +176,9 @@ export const HUMANIZED_BRANCH_TYPE_TEXT_DICT = {
   [GROUP_DEFAULT_BRANCHES.value]: s__('SecurityOrchestration|any default branch'),
   [PROJECT_DEFAULT_BRANCH.value]: s__('SecurityOrchestration|the default branch'),
 };
+
+export const MULTIPLE_SELECTED_LABEL = s__(
+  'PolicyRuleMultiSelect|%{firstLabel} +%{numberOfAdditionalLabels} more',
+);
+export const SELECTED_ITEMS_LABEL = s__('PolicyRuleMultiSelect|Select %{itemTypeName}');
+export const ALL_SELECTED_LABEL = s__('PolicyRuleMultiSelect|All %{itemTypeName}');
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue
index 4be5b830ca7a09ecda1a6c9a62345c82ee2fd0bf..7f6a08025f60b91ef7d6b8ad3576562b9c15716c 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue
@@ -15,7 +15,7 @@ import { __, s__, sprintf } from '~/locale';
 import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import SegmentedControlButtonGroup from '~/vue_shared/components/segmented_control_button_group.vue';
 import DimDisableContainer from 'ee/security_orchestration/components/policy_editor/dim_disable_container.vue';
-import PolicyScope from 'ee/security_orchestration/components/policy_editor/scope/policy_scope.vue';
+import ScopeSection from 'ee/security_orchestration/components/policy_editor/scope/scope_section.vue';
 import { NAMESPACE_TYPES } from '../../constants';
 import { POLICY_TYPE_COMPONENT_OPTIONS } from '../constants';
 import {
@@ -46,7 +46,7 @@ export default {
   ],
   components: {
     DimDisableContainer,
-    PolicyScope,
+    ScopeSection,
     GlAlert,
     GlButton,
     GlFormGroup,
@@ -257,7 +257,10 @@ export default {
                 <div class="gl-bg-gray-10 gl-rounded-base gl-p-6"></div>
               </template>
 
-              <policy-scope />
+              <scope-section
+                :policy-scope="policy.policy_scope"
+                @changed="setPolicyProperty('policy_scope', $event)"
+              />
             </dim-disable-container>
 
             <slot name="actions-first"></slot>
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/rule_multi_select.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/rule_multi_select.vue
index 53c3557a1d9b265f592d1b76bf2efa13d69df3e7..5a709f64a1ec7be8770e1254b92417168a9e39fe 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/rule_multi_select.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/rule_multi_select.vue
@@ -2,9 +2,7 @@
 import { GlCollapsibleListbox, GlTruncate } from '@gitlab/ui';
 
 import { s__, sprintf } from '~/locale';
-
-const NO_ITEM_SELECTED = 0;
-const ONE_ITEM_SELECTED = 1;
+import { renderMultiSelectText } from './utils';
 
 export default {
   components: {
@@ -49,29 +47,7 @@ export default {
       return this.includeSelectAll ? this.$options.i18n.selectAllLabel : '';
     },
     text() {
-      switch (this.selected.length) {
-        case this.itemsKeys.length:
-          return sprintf(
-            this.$options.i18n.allSelectedLabel,
-            { itemTypeName: this.itemTypeName },
-            false,
-          );
-        case NO_ITEM_SELECTED:
-          return sprintf(
-            this.$options.i18n.selectedItemsLabel,
-            {
-              itemTypeName: this.itemTypeName,
-            },
-            false,
-          );
-        case ONE_ITEM_SELECTED:
-          return this.items[this.selected[0]];
-        default:
-          return sprintf(this.$options.i18n.multipleSelectedLabel, {
-            firstLabel: this.items[this.selected[0]],
-            numberOfAdditionalLabels: this.selected.length - 1,
-          });
-      }
+      return renderMultiSelectText(this.selected, this.items, this.itemTypeName);
     },
     itemsKeys() {
       return Object.keys(this.items);
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js
index a72513bb55e4a2d88d267d5aba869417eaadb3fb..408a31d08ee52acd9aafdc63925374d4c787411b 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js
@@ -2,6 +2,7 @@ import { safeLoad } from 'js-yaml';
 import { isValidPolicy, hasInvalidCron } from '../../utils';
 import {
   BRANCH_TYPE_KEY,
+  PRIMARY_POLICY_KEYS,
   RULE_MODE_SCANNERS,
   VALID_SCAN_EXECUTION_BRANCH_TYPE_OPTIONS,
 } from '../../constants';
@@ -65,7 +66,15 @@ export const fromYaml = ({ manifest, validateRuleMode = false }) => {
       ];
       const actionsKeys = ['scan', 'site_profile', 'scanner_profile', 'variables', 'tags'];
 
-      return isValidPolicy({ policy, rulesKeys, actionsKeys }) &&
+      /**
+       * Can be removed after ff is enabled
+       */
+      const primaryKeys = PRIMARY_POLICY_KEYS;
+      if (gon?.features?.securityPoliciesPolicyScope) {
+        primaryKeys.push('policy_scope');
+      }
+
+      return isValidPolicy({ policy, primaryKeys, rulesKeys, actionsKeys }) &&
         !hasInvalidCron(policy) &&
         !hasInvalidBranchType(policy.rules) &&
         hasRuleModeSupportedScanners(policy)
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/from_yaml.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/from_yaml.js
index 9783fc1756e0f1c8ec4d5aca82a2a5eb293614a4..8542b698f4d9409373134d74428f06869bf24a43 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/from_yaml.js
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/from_yaml.js
@@ -32,6 +32,7 @@ export const fromYaml = ({ manifest, validateRuleMode = false }) => {
         ...(hasApprovalSettings || isEqual(policy.approval_settings, PERMITTED_INVALID_SETTINGS) // Temporary workaround to allow the rule builder to load with wrongly persisted settings
           ? [`approval_settings`]
           : []),
+        ...(gon?.features?.securityPoliciesPolicyScope ? ['policy_scope'] : []),
       ];
       const rulesKeys = [
         'type',
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown.vue
index 0815d86309cd8359b2053d84870e9927b081c40b..cc280974751c550e903f175a3d99d3df6c278c29 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown.vue
@@ -1,8 +1,11 @@
 <script>
 import { debounce } from 'lodash';
 import { GlButton, GlCollapsibleListbox, GlLabel } from '@gitlab/ui';
-import { n__, s__, __ } from '~/locale';
+import { s__, __ } from '~/locale';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { TYPE_COMPLIANCE_FRAMEWORK } from '~/graphql_shared/constants';
 import getComplianceFrameworkQuery from 'ee/graphql_shared/queries/get_compliance_framework.query.graphql';
+import { renderMultiSelectText } from 'ee/security_orchestration/components/policy_editor/utils';
 import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
 import ComplianceFrameworkFormModal from 'ee/groups/settings/compliance_frameworks/components/form_modal.vue';
 
@@ -10,7 +13,7 @@ export default {
   i18n: {
     complianceFrameworkCreateButton: s__('SecurityOrchestration|Create new framework label'),
     complianceFrameworkHeader: s__('SecurityOrchestration|Select frameworks'),
-    complianceFrameworkPlaceholder: s__('SecurityOrchestration|Choose framework labels'),
+    complianceFrameworkTypeName: s__('SecurityOrchestration|compliance frameworks'),
     errorMessage: s__('SecurityOrchestration|At least one framework label should be selected'),
     noFrameworksText: s__('SecurityOrchestration|No compliance frameworks'),
     selectAllLabel: __('Select all'),
@@ -61,6 +64,18 @@ export default {
       required: false,
       default: false,
     },
+    /**
+     * selected ids passed as short format
+     * [21,34,45] as number
+     * needs to be converted to full graphql id
+     * if false, selectedFrameworkIds needs to be
+     * an array of full graphQl ids
+     */
+    useShortIdFormat: {
+      type: Boolean,
+      required: false,
+      default: true,
+    },
   },
   data() {
     return {
@@ -69,22 +84,34 @@ export default {
     };
   },
   computed: {
-    dropdownPlaceholder() {
-      if (
-        this.selectedFrameworkIds.length === this.complianceFrameworks?.length &&
-        this.complianceFrameworks?.length > 0
-      ) {
-        return __('All frameworks selected');
-      }
-      if (this.selectedFrameworkIds.length) {
-        return n__(
-          '%d compliance framework selected',
-          '%d compliance frameworks selected',
-          this.selectedFrameworkIds.length,
+    formattedSelectedFrameworkIds() {
+      if (this.useShortIdFormat) {
+        return (
+          this.selectedFrameworkIds?.map((id) =>
+            convertToGraphQLId(TYPE_COMPLIANCE_FRAMEWORK, id),
+          ) || []
         );
       }
 
-      return this.$options.i18n.complianceFrameworkPlaceholder;
+      return this.selectedFrameworkIds || [];
+    },
+    existingFormattedSelectedFrameworkIds() {
+      return this.formattedSelectedFrameworkIds.filter((id) =>
+        this.complianceFrameworkIds.includes(id),
+      );
+    },
+    complianceFrameworkItems() {
+      return this.complianceFrameworks?.reduce((acc, { id, name }) => {
+        acc[id] = name;
+        return acc;
+      }, {});
+    },
+    dropdownPlaceholder() {
+      return renderMultiSelectText(
+        this.formattedSelectedFrameworkIds,
+        this.complianceFrameworkItems,
+        this.$options.i18n.complianceFrameworkTypeName,
+      );
     },
     listBoxItems() {
       return (
@@ -130,10 +157,11 @@ export default {
      * Only works with ListBox multiple mode
      * Without multiple prop select method emits single id
      * and includes method won't work
-     * @param ids selected ids
+     * @param ids selected ids in full graphql format
      */
     selectFrameworks(ids) {
-      this.$emit('select', ids);
+      const payload = this.useShortIdFormat ? ids.map((id) => getIdFromGraphQLId(id)) : ids;
+      this.$emit('select', payload);
     },
     onComplianceFrameworkCreated() {
       this.$refs.formModal.hide();
@@ -158,7 +186,7 @@ export default {
       :show-select-all-button-label="$options.i18n.selectAllLabel"
       :toggle-text="dropdownPlaceholder"
       :title="dropdownPlaceholder"
-      :selected="selectedFrameworkIds"
+      :selected="existingFormattedSelectedFrameworkIds"
       @reset="selectFrameworks([])"
       @search="debouncedSearch"
       @select="selectFrameworks"
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/constants.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/constants.js
index 2b7e9efa57ec629b51bb1fe0f0abf06dd8d973e6..32c366b4ea08c6735bdd9474cc1f6d9a0b371cc9 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/constants.js
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/constants.js
@@ -20,6 +20,10 @@ export const PROJECT_SCOPE_TYPE_LISTBOX_ITEMS = mapToListBoxItems(PROJECT_SCOPE_
 
 export const WITHOUT_EXCEPTIONS = 'without_exceptions';
 export const EXCEPT_PROJECTS = 'except_projects';
+export const INCLUDING = 'including';
+export const EXCLUDING = 'excluding';
+export const COMPLIANCE_FRAMEWORKS_KEY = 'compliance_frameworks';
+export const PROJECTS_KEY = 'projects';
 
 export const EXCEPTION_TYPE_TEXTS = {
   [WITHOUT_EXCEPTIONS]: s__('SecurityOrchestration|without exceptions'),
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/policy_scope.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/scope_section.vue
similarity index 63%
rename from ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/policy_scope.vue
rename to ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/scope_section.vue
index 5e86b636779b90c4fdcf7d3ae95c3123d7b44af5..d76a244744bdafd8017f4f6f62ee7196a8422161 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/policy_scope.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/scope_section.vue
@@ -14,6 +14,10 @@ import {
   SPECIFIC_PROJECTS,
   EXCEPT_PROJECTS,
   ALL_PROJECTS_IN_GROUP,
+  INCLUDING,
+  EXCLUDING,
+  COMPLIANCE_FRAMEWORKS_KEY,
+  PROJECTS_KEY,
 } from './constants';
 
 export default {
@@ -31,7 +35,7 @@ export default {
       'SecurityOrchestration|Failed to load compliance frameworks',
     ),
   },
-  name: 'PolicyScope',
+  name: 'ScopeSection',
   components: {
     GlAlert,
     GlCollapsibleListbox,
@@ -41,17 +45,59 @@ export default {
     GroupProjectsDropdown,
   },
   inject: ['namespacePath', 'rootNamespacePath'],
+  props: {
+    policyScope: {
+      type: Object,
+      required: true,
+      default: () => ({}),
+    },
+  },
   data() {
+    let selectedProjectScopeType = PROJECTS_WITH_FRAMEWORK;
+    let selectedExceptionType = WITHOUT_EXCEPTIONS;
+    let projectsPayloadKey = EXCLUDING;
+
+    const { projects = [] } = this.policyScope || {};
+
+    if (projects?.excluding) {
+      selectedProjectScopeType = ALL_PROJECTS_IN_GROUP;
+      selectedExceptionType = EXCEPT_PROJECTS;
+    }
+
+    if (projects?.including) {
+      selectedProjectScopeType = SPECIFIC_PROJECTS;
+      projectsPayloadKey = INCLUDING;
+    }
+
     return {
-      selectedProjectScopeType: PROJECTS_WITH_FRAMEWORK,
-      selectedExceptionType: WITHOUT_EXCEPTIONS,
-      selectedProjectIds: [],
-      selectedFrameworkIds: [],
+      selectedProjectScopeType,
+      selectedExceptionType,
+      projectsPayloadKey,
       showAlert: false,
       errorDescription: '',
     };
   },
   computed: {
+    projectIds() {
+      /**
+       * Protection from manual yam input as objects
+       * @type {*|*[]}
+       */
+      const projects = Array.isArray(this.policyScope?.projects?.[this.projectsPayloadKey])
+        ? this.policyScope?.projects?.[this.projectsPayloadKey]
+        : [];
+      return projects?.map(({ id }) => id) || [];
+    },
+    complianceFrameworksIds() {
+      /**
+       * Protection from manual yam input as objects
+       * @type {*|*[]}
+       */
+      const frameworks = Array.isArray(this.policyScope?.compliance_frameworks)
+        ? this.policyScope?.compliance_frameworks
+        : [];
+      return frameworks?.map(({ id }) => id) || [];
+    },
     selectedProjectScopeText() {
       return PROJECT_SCOPE_TYPE_TEXTS[this.selectedProjectScopeType];
     },
@@ -67,6 +113,11 @@ export default {
         this.selectedProjectScopeType === SPECIFIC_PROJECTS
       );
     },
+    payloadKey() {
+      return this.selectedProjectScopeType === PROJECTS_WITH_FRAMEWORK
+        ? COMPLIANCE_FRAMEWORKS_KEY
+        : PROJECTS_KEY;
+    },
     policyScopeCopy() {
       return this.selectedProjectScopeType === PROJECTS_WITH_FRAMEWORK
         ? this.$options.i18n.policyScopeFrameworkCopy
@@ -74,17 +125,37 @@ export default {
     },
   },
   methods: {
+    resetPolicyScope() {
+      const internalPayload =
+        this.payloadKey === COMPLIANCE_FRAMEWORKS_KEY ? [] : { [this.projectsPayloadKey]: [] };
+      const payload = {
+        [this.payloadKey]: internalPayload,
+      };
+
+      this.$emit('changed', payload);
+    },
     selectProjectScopeType(scopeType) {
       this.selectedProjectScopeType = scopeType;
+      this.projectsPayloadKey =
+        this.selectedProjectScopeType === ALL_PROJECTS_IN_GROUP ? EXCLUDING : INCLUDING;
+      this.resetPolicyScope();
     },
     selectExceptionType(type) {
       this.selectedExceptionType = type;
+      this.resetPolicyScope();
     },
     setSelectedProjectIds(ids) {
-      this.selectedProjectIds = ids;
+      const projects = ids.map((id) => ({ id }));
+      const payload = { projects: { [this.projectsPayloadKey]: projects } };
+
+      this.triggerChanged(payload);
     },
     setSelectedFrameworkIds(ids) {
-      this.selectedFrameworkIds = ids;
+      const payload = ids.map((id) => ({ id }));
+      this.triggerChanged({ compliance_frameworks: payload });
+    },
+    triggerChanged(value) {
+      this.$emit('changed', { ...this.policyScope, ...value });
     },
     setShowAlert(errorDescription) {
       this.showAlert = true;
@@ -104,6 +175,7 @@ export default {
       <gl-sprintf :message="policyScopeCopy">
         <template #projectScopeType>
           <gl-collapsible-listbox
+            data-testid="project-scope-type"
             :items="$options.PROJECT_SCOPE_TYPE_LISTBOX_ITEMS"
             :selected="selectedProjectScopeType"
             :toggle-text="selectedProjectScopeText"
@@ -114,7 +186,7 @@ export default {
         <template #frameworkSelector>
           <div class="gl-display-inline-flex gl-align-items-center gl-flex-wrap gl-gap-3">
             <compliance-framework-dropdown
-              :selected-framework-ids="selectedFrameworkIds"
+              :selected-framework-ids="complianceFrameworksIds"
               :full-path="rootNamespacePath"
               @framework-query-error="
                 setShowAlert($options.i18n.complianceFrameworkErrorDescription)
@@ -129,6 +201,7 @@ export default {
         <template #exceptionType>
           <gl-collapsible-listbox
             v-if="showExceptionTypeDropdown"
+            data-testid="exception-type"
             :items="$options.EXCEPTION_TYPE_LISTBOX_ITEMS"
             :toggle-text="selectedExceptionTypeText"
             :selected="selectedExceptionType"
@@ -140,7 +213,7 @@ export default {
           <group-projects-dropdown
             v-if="showGroupProjectsDropdown"
             :group-full-path="namespacePath"
-            :selected-projects-ids="selectedProjectIds"
+            :selected-projects-ids="projectIds"
             @projects-query-error="setShowAlert($options.i18n.groupProjectErrorDescription)"
             @select="setSelectedProjectIds"
           />
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/utils.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/utils.js
index 4866970dbf0ac9f7e562e66d426600b77fa6ce1b..17c045df89e48e61d4d9eeff985645627da513bd 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/utils.js
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/utils.js
@@ -1,4 +1,6 @@
+import { intersection } from 'lodash';
 import { isValidCron } from 'cron-validator';
+import { sprintf } from '~/locale';
 import createPolicyProject from 'ee/security_orchestration/graphql/mutations/create_policy_project.mutation.graphql';
 import createScanExecutionPolicy from 'ee/security_orchestration/graphql/mutations/create_scan_execution_policy.mutation.graphql';
 import { gqClient } from 'ee/security_orchestration/utils';
@@ -11,6 +13,9 @@ import {
   PRIMARY_POLICY_KEYS,
   RULE_MODE_SCANNERS,
   SECURITY_POLICY_ACTIONS,
+  ALL_SELECTED_LABEL,
+  SELECTED_ITEMS_LABEL,
+  MULTIPLE_SELECTED_LABEL,
 } from './constants';
 
 /**
@@ -225,3 +230,55 @@ export const hasInvalidCron = (policy) => {
 };
 
 export const enforceIntValue = (value) => parseInt(value || '0', 10);
+
+const NO_ITEM_SELECTED = 0;
+const ONE_ITEM_SELECTED = 1;
+
+/**
+ *
+ * @param selected items
+ * @param items items used to render list
+ * @param itemTypeName
+ * @returns {*}
+ */
+export const renderMultiSelectText = (selected, items, itemTypeName) => {
+  const itemsKeys = Object.keys(items);
+
+  const defaultPlaceholder = sprintf(
+    SELECTED_ITEMS_LABEL,
+    {
+      itemTypeName,
+    },
+    false,
+  );
+
+  /**
+   * Another edge case
+   * number of selected items and items are equal
+   * but none of them match
+   * without this check it would fall through to
+   * ALL_SELECTED_LABEL
+   * @type {string[]}
+   */
+  const commonItems = intersection(itemsKeys, selected);
+  /**
+   * Edge case for loading states when initial items are empty
+   */
+  if (itemsKeys.length === 0 || commonItems.length === 0) {
+    return defaultPlaceholder;
+  }
+
+  switch (commonItems.length) {
+    case itemsKeys.length:
+      return sprintf(ALL_SELECTED_LABEL, { itemTypeName }, false);
+    case NO_ITEM_SELECTED:
+      return defaultPlaceholder;
+    case ONE_ITEM_SELECTED:
+      return items[commonItems[0]] || defaultPlaceholder;
+    default:
+      return sprintf(MULTIPLE_SELECTED_LABEL, {
+        firstLabel: items[commonItems[0]],
+        numberOfAdditionalLabels: commonItems.length - 1,
+      });
+  }
+};
diff --git a/ee/spec/frontend/security_orchestration/components/group_projects_dropdown_spec.js b/ee/spec/frontend/security_orchestration/components/group_projects_dropdown_spec.js
index dbefa4dc7920142e66c52229ec0f9340200c2276..7d19e0ae68958d423cbcab34227432d116f9997e 100644
--- a/ee/spec/frontend/security_orchestration/components/group_projects_dropdown_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/group_projects_dropdown_spec.js
@@ -2,6 +2,8 @@ import Vue, { nextTick } from 'vue';
 import VueApollo from 'vue-apollo';
 import { shallowMount } from '@vue/test-utils';
 import { GlCollapsibleListbox } from '@gitlab/ui';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { TYPENAME_PROJECT } from '~/graphql_shared/constants';
 import createMockApollo from 'helpers/mock_apollo_helper';
 import waitForPromises from 'helpers/wait_for_promises';
 import getGroupProjects from 'ee/security_orchestration/graphql/queries/get_group_projects.query.graphql';
@@ -12,8 +14,8 @@ describe('GroupProjectsDropdown', () => {
   let requestHandlers;
 
   const defaultNodes = [
-    { id: 1, name: '1', fullPath: 'project-1-full-path' },
-    { id: 2, name: '2', fullPath: 'project-2-full-path' },
+    { id: convertToGraphQLId(TYPENAME_PROJECT, 1), name: '1', fullPath: 'project-1-full-path' },
+    { id: convertToGraphQLId(TYPENAME_PROJECT, 2), name: '2', fullPath: 'project-2-full-path' },
   ];
 
   const defaultNodesIds = defaultNodes.map(({ id }) => id);
@@ -84,14 +86,16 @@ describe('GroupProjectsDropdown', () => {
     const [{ id }] = defaultNodes;
 
     await waitForPromises();
-    findDropdown().vm.$emit('select', id);
-    expect(wrapper.emitted('select')).toEqual([[id]]);
+    findDropdown().vm.$emit('select', [id]);
+    expect(wrapper.emitted('select')).toEqual([[[getIdFromGraphQLId(id)]]]);
   });
 
   it('should select all projects', async () => {
     await waitForPromises();
     selectAllProjects();
-    expect(wrapper.emitted('select')).toEqual([[defaultNodesIds]]);
+    expect(wrapper.emitted('select')).toEqual([
+      [defaultNodesIds.map((id) => getIdFromGraphQLId(id))],
+    ]);
   });
 
   it('renders default text when loading', () => {
@@ -114,7 +118,7 @@ describe('GroupProjectsDropdown', () => {
 
     it('renders all projects selected text when', async () => {
       await waitForPromises();
-      expect(findDropdown().props('toggleText')).toBe('All projects selected');
+      expect(findDropdown().props('toggleText')).toBe('All projects');
     });
 
     it('should reset all projects', async () => {
@@ -125,6 +129,32 @@ describe('GroupProjectsDropdown', () => {
     });
   });
 
+  describe('selected projects that does not exist', () => {
+    it('renders default placeholder when selected projects do not exist', async () => {
+      createComponent({
+        propsData: {
+          selectedProjectsIds: ['one', 'two'],
+        },
+      });
+
+      await waitForPromises();
+      expect(findDropdown().props('toggleText')).toBe('Select projects');
+    });
+
+    it('filters selected projects that does not exist', async () => {
+      createComponent({
+        propsData: {
+          selectedProjectsIds: ['one', 'two'],
+        },
+      });
+
+      await waitForPromises();
+      findDropdown().vm.$emit('select', [defaultNodesIds[0]]);
+
+      expect(wrapper.emitted('select')).toEqual([[[getIdFromGraphQLId(defaultNodesIds[0])]]]);
+    });
+  });
+
   describe('when there is more than a page of projects', () => {
     describe('when bottom reached on scrolling', () => {
       it('makes a query to fetch more projects', async () => {
@@ -160,4 +190,32 @@ describe('GroupProjectsDropdown', () => {
       });
     });
   });
+
+  describe('full id format', () => {
+    it('should emit full format of id', async () => {
+      createComponent({
+        propsData: {
+          useShortIdFormat: false,
+        },
+      });
+
+      await waitForPromises();
+      selectAllProjects();
+
+      expect(wrapper.emitted('select')).toEqual([[defaultNodesIds]]);
+    });
+
+    it('should render selected ids in full format', async () => {
+      createComponent({
+        propsData: {
+          selectedProjectsIds: defaultNodesIds,
+          useShortIdFormat: false,
+        },
+      });
+
+      await waitForPromises();
+
+      expect(findDropdown().props('selected')).toEqual(defaultNodesIds);
+    });
+  });
 });
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/editor_layout_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/editor_layout_spec.js
index afd5481b2ce6c824bfb499aebb0a612ab74df937..ac1775b7306bfcfd03bb059d86ebd6d3ec4a2c35 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/editor_layout_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/editor_layout_spec.js
@@ -17,7 +17,7 @@ import {
 import { NAMESPACE_TYPES } from 'ee/security_orchestration/constants';
 import SegmentedControlButtonGroup from '~/vue_shared/components/segmented_control_button_group.vue';
 import EditorLayout from 'ee/security_orchestration/components/policy_editor/editor_layout.vue';
-import PolicyScope from 'ee/security_orchestration/components/policy_editor/scope/policy_scope.vue';
+import ScopeSection from 'ee/security_orchestration/components/policy_editor/scope/scope_section.vue';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 import { mockDastScanExecutionObject } from '../../mocks/mock_scan_execution_policy_data';
 import { mockDefaultBranchesScanResultObject } from '../../mocks/mock_scan_result_policy_data';
@@ -65,7 +65,7 @@ describe('EditorLayout component', () => {
     wrapper.findByTestId('scan-result-policy-run-time-info');
   const findScanResultPolicyRunTimeTooltip = () =>
     findScanResultPolicyRunTimeInfo().findComponent(GlIcon);
-  const findPolicyScope = () => wrapper.findComponent(PolicyScope);
+  const findScopeSection = () => wrapper.findComponent(ScopeSection);
 
   describe('default behavior', () => {
     beforeEach(() => {
@@ -314,8 +314,22 @@ describe('EditorLayout component', () => {
           },
         });
 
-        expect(findPolicyScope().exists()).toBe(expectedResult);
+        expect(findScopeSection().exists()).toBe(expectedResult);
       },
     );
+
+    it('should set policy properties', () => {
+      const payload = { policy_scope: { compliance_frameworks: [{ id: 'test' }] } };
+
+      factory({
+        provide: {
+          namespaceType: NAMESPACE_TYPES.GROUP,
+          glFeatures: { securityPoliciesPolicyScope: true },
+        },
+      });
+
+      findScopeSection().vm.$emit('changed', payload);
+      expect(wrapper.emitted('set-policy-property')).toEqual([['policy_scope', payload]]);
+    });
   });
 });
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js
index 928d552bdf1ac0f1605507b22f6bbf3507d9b415..e3488b0d7fbdbed9b327e2af540237b2d4634ef2 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js
@@ -14,18 +14,23 @@ import {
   mockInvalidYamlCadenceValue,
   mockBranchExceptionsScanExecutionObject,
   mockBranchExceptionsExecutionManifest,
+  mockPolicyScopeExecutionManifest,
+  mockPolicyScopeScanExecutionObject,
 } from 'ee_jest/security_orchestration/mocks/mock_scan_execution_policy_data';
 
 describe('fromYaml', () => {
   it.each`
-    title                                                                                                | input                                                                          | output
-    ${'returns the policy object for a supported manifest'}                                              | ${{ manifest: mockDastScanExecutionManifest }}                                 | ${mockDastScanExecutionObject}
-    ${'returns the error object for a policy with an unsupported attribute'}                             | ${{ manifest: unsupportedManifest, validateRuleMode: true }}                   | ${{ error: true }}
-    ${'returns the policy object for a policy with an unsupported attribute when validation is skipped'} | ${{ manifest: unsupportedManifest }}                                           | ${unsupportedManifestObject}
-    ${'returns error object for a policy with invalid cadence cron string and validation mode'}          | ${{ manifest: mockInvalidCadenceScanExecutionObject, validateRuleMode: true }} | ${{ error: true }}
-    ${'returns error object for a policy with invalid cadence cron string'}                              | ${{ manifest: mockInvalidYamlCadenceValue }}                                   | ${{ error: true, key: 'yaml-parsing' }}
-    ${'returns the policy object for branch exceptions'}                                                 | ${{ manifest: mockBranchExceptionsExecutionManifest, validateRuleMode: true }} | ${mockBranchExceptionsScanExecutionObject}
-  `('$title', ({ input, output }) => {
+    title                                                                                                | input                                                                          | output                                     | features
+    ${'returns the policy object for a supported manifest'}                                              | ${{ manifest: mockDastScanExecutionManifest }}                                 | ${mockDastScanExecutionObject}             | ${{}}
+    ${'returns the error object for a policy with an unsupported attribute'}                             | ${{ manifest: unsupportedManifest, validateRuleMode: true }}                   | ${{ error: true }}                         | ${{}}
+    ${'returns the policy object for a policy with an unsupported attribute when validation is skipped'} | ${{ manifest: unsupportedManifest }}                                           | ${unsupportedManifestObject}               | ${{}}
+    ${'returns error object for a policy with invalid cadence cron string and validation mode'}          | ${{ manifest: mockInvalidCadenceScanExecutionObject, validateRuleMode: true }} | ${{ error: true }}                         | ${{}}
+    ${'returns error object for a policy with invalid cadence cron string'}                              | ${{ manifest: mockInvalidYamlCadenceValue }}                                   | ${{ error: true, key: 'yaml-parsing' }}    | ${{}}
+    ${'returns the policy object for branch exceptions'}                                                 | ${{ manifest: mockBranchExceptionsExecutionManifest, validateRuleMode: true }} | ${mockBranchExceptionsScanExecutionObject} | ${{}}
+    ${'returns the policy object for project scope with disabled ff'}                                    | ${{ manifest: mockPolicyScopeExecutionManifest, validateRuleMode: true }}      | ${{ error: true }}                         | ${{ securityPoliciesPolicyScope: false }}
+    ${'returns the policy object for project scope with enabled ff'}                                     | ${{ manifest: mockPolicyScopeExecutionManifest, validateRuleMode: true }}      | ${mockPolicyScopeScanExecutionObject}      | ${{ securityPoliciesPolicyScope: true }}
+  `('$title', ({ input, output, features }) => {
+    window.gon = { features };
     expect(fromYaml(input)).toStrictEqual(output);
   });
 });
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/lib/from_yaml_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/lib/from_yaml_spec.js
index 6c8bf701b5cb22a06fc37c5a4ed0d5887a9766d2..0f16a671ba0fdd706e0b4e2283c30ea8e9a2024b 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/lib/from_yaml_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/lib/from_yaml_spec.js
@@ -10,6 +10,8 @@ import {
   mockApprovalSettingsScanResultObject,
   mockApprovalSettingsPermittedInvalidScanResultManifest,
   mockApprovalSettingsPermittedInvalidScanResultObject,
+  mockPolicyScopeScanResultManifest,
+  mockPolicyScopeScanResultObject,
 } from 'ee_jest/security_orchestration/mocks/mock_scan_result_policy_data';
 import {
   unsupportedManifest,
@@ -97,9 +99,12 @@ describe('createPolicyObject', () => {
       title                                                                                                                                                                              | features                                                 | input                                                     | output
       ${'returns the policy object for a manifest with `approval_settings` with the `scanResultPoliciesBlockUnprotectingBranches` feature flag on'}                                      | ${{ scanResultPoliciesBlockUnprotectingBranches: true }} | ${mockApprovalSettingsScanResultManifest}                 | ${{ policy: mockApprovalSettingsScanResultObject, hasParsingError: false }}
       ${'returns the policy object for a manifest with `approval_settings` containing permitted invalid settings and the `scanResultPoliciesBlockUnprotectingBranches` feature flag on'} | ${{ scanResultPoliciesBlockUnprotectingBranches: true }} | ${mockApprovalSettingsPermittedInvalidScanResultManifest} | ${{ policy: mockApprovalSettingsPermittedInvalidScanResultObject, hasParsingError: false }}
+      ${'returns the policy object for a manifest with `policy_scope` feature flag on'}                                                                                                  | ${{ securityPoliciesPolicyScope: true }}                 | ${mockPolicyScopeScanResultManifest}                      | ${{ policy: mockPolicyScopeScanResultObject, hasParsingError: false }}
       ${'returns the error object for a manifest with `approval_settings` containing permitted invalid settings and the `scanResultPoliciesBlockUnprotectingBranches` feature flag off'} | ${{}}                                                    | ${mockApprovalSettingsPermittedInvalidScanResultManifest} | ${{ policy: mockApprovalSettingsPermittedInvalidScanResultObject, hasParsingError: false }}
       ${'returns the policy object for a manifest with `approval_settings` with the `scanResultAnyMergeRequest` feature flag on'}                                                        | ${{ scanResultAnyMergeRequest: true }}                   | ${mockApprovalSettingsScanResultManifest}                 | ${{ policy: mockApprovalSettingsScanResultObject, hasParsingError: false }}
       ${'returns the error object for a manifest with `approval_settings` with all feature flags off'}                                                                                   | ${{}}                                                    | ${mockApprovalSettingsScanResultManifest}                 | ${{ policy: { error: true }, hasParsingError: true }}
+      ${'returns the error object for a manifest with `approval_settings` with all feature flags off'}                                                                                   | ${{}}                                                    | ${mockApprovalSettingsScanResultManifest}                 | ${{ policy: { error: true }, hasParsingError: true }}
+      ${'returns the error object for a manifest with `policy_scope` feature flag off'}                                                                                                  | ${{}}                                                    | ${mockPolicyScopeScanResultManifest}                      | ${{ policy: { error: true }, hasParsingError: true }}
     `('$title', ({ features, input, output }) => {
       window.gon = { features };
       expect(createPolicyObject(input)).toStrictEqual(output);
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown_spec.js
index 7a0450bd32fbf12218548fa2ea2ac14e3390b7c7..15b22e5a5f7db2998fff93b78e58564e72a87237 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown_spec.js
@@ -3,6 +3,8 @@ import VueApollo from 'vue-apollo';
 import { GlButton, GlCollapsibleListbox, GlModal } from '@gitlab/ui';
 import createMockApollo from 'helpers/mock_apollo_helper';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { TYPE_COMPLIANCE_FRAMEWORK } from '~/graphql_shared/constants';
 import ComplianceFrameworkDropdown from 'ee/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown.vue';
 import ComplianceFrameworkFormModal from 'ee/groups/settings/compliance_frameworks/components/form_modal.vue';
 import CreateForm from 'ee/groups/settings/compliance_frameworks/components/create_form.vue';
@@ -22,7 +24,7 @@ describe('ComplianceFrameworkDropdown', () => {
 
   const defaultNodes = [
     {
-      id: 1,
+      id: convertToGraphQLId(TYPE_COMPLIANCE_FRAMEWORK, 1),
       name: 'A1',
       default: true,
       description: 'description 1',
@@ -30,7 +32,7 @@ describe('ComplianceFrameworkDropdown', () => {
       pipelineConfigurationFullPath: 'path 1',
     },
     {
-      id: 2,
+      id: convertToGraphQLId(TYPE_COMPLIANCE_FRAMEWORK, 2),
       name: 'B2',
       default: false,
       description: 'description 2',
@@ -38,7 +40,7 @@ describe('ComplianceFrameworkDropdown', () => {
       pipelineConfigurationFullPath: 'path 2',
     },
     {
-      id: 3,
+      id: convertToGraphQLId(TYPE_COMPLIANCE_FRAMEWORK, 3),
       name: 'a3',
       default: true,
       description: 'description 3',
@@ -131,18 +133,20 @@ describe('ComplianceFrameworkDropdown', () => {
       const [{ id }] = defaultNodes;
 
       await waitForPromises();
-      findDropdown().vm.$emit('select', id);
-      expect(wrapper.emitted('select')).toEqual([[id]]);
+      findDropdown().vm.$emit('select', [id]);
+      expect(wrapper.emitted('select')).toEqual([[[getIdFromGraphQLId(id)]]]);
     });
 
     it('should select all frameworks', async () => {
       await waitForPromises();
       selectAll();
-      expect(wrapper.emitted('select')).toEqual([[defaultNodesIds]]);
+      expect(wrapper.emitted('select')).toEqual([
+        [defaultNodesIds.map((id) => getIdFromGraphQLId(id))],
+      ]);
     });
 
     it('renders default text when loading', () => {
-      expect(findDropdown().props('toggleText')).toBe('Choose framework labels');
+      expect(findDropdown().props('toggleText')).toBe('Select compliance frameworks');
     });
 
     it('should search frameworks despite case', async () => {
@@ -192,7 +196,7 @@ describe('ComplianceFrameworkDropdown', () => {
         handlers: mockApolloHandlers([]),
       });
       await waitForPromises();
-      expect(findDropdown().props('toggleText')).toBe('Choose framework labels');
+      expect(findDropdown().props('toggleText')).toBe('Select compliance frameworks');
     });
   });
 
@@ -212,7 +216,7 @@ describe('ComplianceFrameworkDropdown', () => {
 
     it('renders all frameworks selected text', async () => {
       await waitForPromises();
-      expect(findDropdown().props('toggleText')).toBe('All frameworks selected');
+      expect(findDropdown().props('toggleText')).toBe('All compliance frameworks');
     });
 
     it('should reset all frameworks', async () => {
@@ -223,6 +227,32 @@ describe('ComplianceFrameworkDropdown', () => {
     });
   });
 
+  describe('selected frameworks that does not exist', () => {
+    it('renders default placeholder when selected frameworks do not exist', async () => {
+      createComponent({
+        propsData: {
+          selectedFrameworkIds: ['one', 'two'],
+        },
+      });
+
+      await waitForPromises();
+      expect(findDropdown().props('toggleText')).toBe('Select compliance frameworks');
+    });
+
+    it('filters selected frameworks that does not exist', async () => {
+      createComponent({
+        propsData: {
+          selectedFrameworkIds: ['one', 'two'],
+        },
+      });
+
+      await waitForPromises();
+      findDropdown().vm.$emit('select', [defaultNodesIds[0]]);
+
+      expect(wrapper.emitted('select')).toEqual([[[getIdFromGraphQLId(defaultNodesIds[0])]]]);
+    });
+  });
+
   describe('one selected project', () => {
     it('should render text for selected framework', async () => {
       createComponent({
@@ -232,7 +262,7 @@ describe('ComplianceFrameworkDropdown', () => {
       });
 
       await waitForPromises();
-      expect(findDropdown().props('toggleText')).toBe('1 compliance framework selected');
+      expect(findDropdown().props('toggleText')).toBe(defaultNodes[0].name);
     });
   });
 
@@ -265,4 +295,32 @@ describe('ComplianceFrameworkDropdown', () => {
       expect(findDropdown().props('category')).toBe(category);
     });
   });
+
+  describe('full id format', () => {
+    it('should emit full format of id', async () => {
+      createComponent({
+        propsData: {
+          useShortIdFormat: false,
+        },
+      });
+
+      await waitForPromises();
+      selectAll();
+
+      expect(wrapper.emitted('select')).toEqual([[defaultNodesIds]]);
+    });
+
+    it('should render selected ids in full format', async () => {
+      createComponent({
+        propsData: {
+          selectedFrameworkIds: defaultNodesIds,
+          useShortIdFormat: false,
+        },
+      });
+
+      await waitForPromises();
+
+      expect(findDropdown().props('selected')).toEqual(defaultNodesIds);
+    });
+  });
 });
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scope/scope_section_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scope/scope_section_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..c64c9305c8b1643e2f4edbc772852a34f48e64e5
--- /dev/null
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scope/scope_section_spec.js
@@ -0,0 +1,223 @@
+import { GlAlert, GlSprintf } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ScopeSection from 'ee/security_orchestration/components/policy_editor/scope/scope_section.vue';
+import ComplianceFrameworkDropdown from 'ee/security_orchestration/components/policy_editor/scope/compliance_framework_dropdown.vue';
+import GroupProjectsDropdown from 'ee/security_orchestration/components/group_projects_dropdown.vue';
+import {
+  PROJECTS_WITH_FRAMEWORK,
+  ALL_PROJECTS_IN_GROUP,
+  SPECIFIC_PROJECTS,
+  EXCEPT_PROJECTS,
+} from 'ee/security_orchestration/components/policy_editor/scope/constants';
+
+describe('PolicyScope', () => {
+  let wrapper;
+
+  const createComponent = ({ propsData } = {}) => {
+    wrapper = shallowMountExtended(ScopeSection, {
+      propsData: {
+        policyScope: {},
+        ...propsData,
+      },
+      provide: {
+        namespacePath: 'gitlab-org',
+        rootNamespacePath: 'gitlab-org',
+      },
+      stubs: {
+        GlSprintf,
+      },
+    });
+  };
+
+  const findGlAlert = () => wrapper.findComponent(GlAlert);
+  const findComplianceFrameworkDropdown = () => wrapper.findComponent(ComplianceFrameworkDropdown);
+  const findGroupProjectsDropdown = () => wrapper.findComponent(GroupProjectsDropdown);
+  const findProjectScopeTypeDropdown = () => wrapper.findByTestId('project-scope-type');
+  const findExceptionTypeDropdown = () => wrapper.findByTestId('exception-type');
+
+  beforeEach(() => {
+    createComponent();
+  });
+
+  it('should render framework dropdown in initial state', () => {
+    expect(findProjectScopeTypeDropdown().props('selected')).toBe(PROJECTS_WITH_FRAMEWORK);
+    expect(findComplianceFrameworkDropdown().exists()).toBe(true);
+
+    expect(findExceptionTypeDropdown().exists()).toBe(false);
+    expect(findGroupProjectsDropdown().exists()).toBe(false);
+    expect(findGlAlert().exists()).toBe(false);
+  });
+
+  it('should change scope and reset it', async () => {
+    await findProjectScopeTypeDropdown().vm.$emit('select', ALL_PROJECTS_IN_GROUP);
+
+    expect(findComplianceFrameworkDropdown().exists()).toBe(false);
+
+    expect(findExceptionTypeDropdown().exists()).toBe(true);
+    expect(findGroupProjectsDropdown().exists()).toBe(false);
+    expect(wrapper.emitted('changed')).toEqual([
+      [
+        {
+          projects: {
+            excluding: [],
+          },
+        },
+      ],
+    ]);
+
+    await findProjectScopeTypeDropdown().vm.$emit('select', SPECIFIC_PROJECTS);
+
+    expect(findExceptionTypeDropdown().exists()).toBe(false);
+    expect(findGroupProjectsDropdown().exists()).toBe(true);
+    expect(wrapper.emitted('changed')).toEqual([
+      [
+        {
+          projects: {
+            excluding: [],
+          },
+        },
+      ],
+      [
+        {
+          projects: {
+            including: [],
+          },
+        },
+      ],
+    ]);
+  });
+
+  it('should select excluding projects', async () => {
+    await findProjectScopeTypeDropdown().vm.$emit('select', ALL_PROJECTS_IN_GROUP);
+
+    expect(findGroupProjectsDropdown().exists()).toBe(false);
+
+    await findExceptionTypeDropdown().vm.$emit('select', EXCEPT_PROJECTS);
+
+    expect(findGroupProjectsDropdown().exists()).toBe(true);
+
+    findGroupProjectsDropdown().vm.$emit('select', ['id1', 'id2']);
+
+    expect(wrapper.emitted('changed')).toEqual([
+      [
+        {
+          projects: {
+            excluding: [],
+          },
+        },
+      ],
+      [
+        {
+          projects: {
+            excluding: [],
+          },
+        },
+      ],
+      [{ projects: { excluding: [{ id: 'id1' }, { id: 'id2' }] } }],
+    ]);
+  });
+
+  it('should select including projects', async () => {
+    await findProjectScopeTypeDropdown().vm.$emit('select', SPECIFIC_PROJECTS);
+
+    expect(findGroupProjectsDropdown().exists()).toBe(true);
+
+    findGroupProjectsDropdown().vm.$emit('select', ['id1', 'id2']);
+
+    expect(wrapper.emitted('changed')).toEqual([
+      [
+        {
+          projects: {
+            including: [],
+          },
+        },
+      ],
+      [{ projects: { including: [{ id: 'id1' }, { id: 'id2' }] } }],
+    ]);
+  });
+
+  it('should select compliance frameworks', () => {
+    findComplianceFrameworkDropdown().vm.$emit('select', ['id1', 'id2']);
+
+    expect(wrapper.emitted('changed')).toEqual([
+      [{ compliance_frameworks: [{ id: 'id1' }, { id: 'id2' }] }],
+    ]);
+  });
+
+  describe('existing policy scope', () => {
+    it('should render existing compliance frameworks', () => {
+      createComponent({
+        propsData: {
+          policyScope: {
+            compliance_frameworks: [{ id: 'id1' }, { id: 'id2' }],
+          },
+        },
+      });
+
+      expect(findComplianceFrameworkDropdown().exists()).toBe(true);
+      expect(findComplianceFrameworkDropdown().props('selectedFrameworkIds')).toEqual([
+        'id1',
+        'id2',
+      ]);
+
+      expect(findExceptionTypeDropdown().exists()).toBe(false);
+      expect(findGroupProjectsDropdown().exists()).toBe(false);
+    });
+
+    it('should render existing excluding projects', () => {
+      createComponent({
+        propsData: {
+          policyScope: {
+            projects: {
+              excluding: [{ id: 'id1' }, { id: 'id2' }],
+            },
+          },
+        },
+      });
+
+      expect(findComplianceFrameworkDropdown().exists()).toBe(false);
+
+      expect(findExceptionTypeDropdown().props('selected')).toBe(EXCEPT_PROJECTS);
+      expect(findExceptionTypeDropdown().exists()).toBe(true);
+      expect(findGroupProjectsDropdown().exists()).toBe(true);
+      expect(findGroupProjectsDropdown().props('selectedProjectsIds')).toEqual(['id1', 'id2']);
+    });
+
+    it('should render existing including projects', () => {
+      createComponent({
+        propsData: {
+          policyScope: {
+            projects: {
+              including: [{ id: 'id1' }, { id: 'id2' }],
+            },
+          },
+        },
+      });
+
+      expect(findComplianceFrameworkDropdown().exists()).toBe(false);
+      expect(findExceptionTypeDropdown().exists()).toBe(false);
+      expect(findGroupProjectsDropdown().exists()).toBe(true);
+      expect(findGroupProjectsDropdown().props('selectedProjectsIds')).toEqual(['id1', 'id2']);
+    });
+
+    it('should render alert message for projects dropdown', async () => {
+      createComponent({
+        propsData: {
+          policyScope: {
+            projects: {
+              including: ['id1', 'id2'],
+            },
+          },
+        },
+      });
+
+      await findGroupProjectsDropdown().vm.$emit('projects-query-error');
+      expect(findGlAlert().exists()).toBe(true);
+    });
+
+    it('should render alert message for compliance framework dropdown', async () => {
+      await findComplianceFrameworkDropdown().vm.$emit('framework-query-error');
+      expect(findGlAlert().exists()).toBe(true);
+    });
+  });
+});
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/utils_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/utils_spec.js
index 571148fc7b5d562e38eb36540116679317627f55..4c9a4dd03ea37ef9dbd099ebdf36118893034810 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/utils_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/utils_spec.js
@@ -6,6 +6,7 @@ import {
   hasInvalidCron,
   slugify,
   slugifyToArray,
+  renderMultiSelectText,
 } from 'ee/security_orchestration/components/policy_editor/utils';
 import { DEFAULT_ASSIGNED_POLICY_PROJECT } from 'ee/security_orchestration/constants';
 import createPolicyProject from 'ee/security_orchestration/graphql/mutations/create_policy_project.mutation.graphql';
@@ -207,3 +208,18 @@ describe('slugifyToArray', () => {
     );
   });
 });
+
+describe('renderMultiSelectText', () => {
+  it.each`
+    selected                    | items                                                                      | expectedText
+    ${[]}                       | ${{}}                                                                      | ${'Select projects'}
+    ${['project1']}             | ${{ project1: 'project 1', project2: 'project 2' }}                        | ${'project 1'}
+    ${['project1', 'project2']} | ${{ project1: 'project 1', project2: 'project 2' }}                        | ${'All projects'}
+    ${['project1', 'project2']} | ${{ project1: 'project 1', project2: 'project 2', project3: 'project 3' }} | ${'project 1 +1 more'}
+    ${[]}                       | ${{ project1: 'project 1', project2: 'project 2', project3: 'project 3' }} | ${'Select projects'}
+    ${['project4', 'project5']} | ${{ project1: 'project 1', project2: 'project 2', project3: 'project 3' }} | ${'Select projects'}
+    ${['project4', 'project5']} | ${{ project2: 'project 2', project3: 'project 3' }}                        | ${'Select projects'}
+  `('should render correct selection text', ({ selected, items, expectedText }) => {
+    expect(renderMultiSelectText(selected, items, 'projects')).toBe(expectedText);
+  });
+});
diff --git a/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js b/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js
index 7d7060b0700bbb042e6cb4a30d8d5bbf7ee882eb..9b3d614899d383a030c3a7306c3d6cbeb7d9bfbb 100644
--- a/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js
+++ b/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js
@@ -211,3 +211,38 @@ export const mockInvalidCadenceScanExecutionObject = {
     },
   ],
 };
+
+export const mockPolicyScopeExecutionManifest = `type: scan_execution_policy
+name: Project scope
+description: This policy enforces policy scope
+enabled: false
+rules:
+  - type: pipeline
+    branches:
+      - main
+actions:
+  - scan: container_scanning
+policy_scope:
+  compliance_frameworks: []
+`;
+
+export const mockPolicyScopeScanExecutionObject = {
+  type: 'scan_execution_policy',
+  name: 'Project scope',
+  enabled: false,
+  description: 'This policy enforces policy scope',
+  rules: [
+    {
+      type: 'pipeline',
+      branches: ['main'],
+    },
+  ],
+  actions: [
+    {
+      scan: 'container_scanning',
+    },
+  ],
+  policy_scope: {
+    compliance_frameworks: [],
+  },
+};
diff --git a/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js b/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js
index 3d0aac9aea837c847e0359d292da9759ca930556..9a50d55a94f3a5531cd693b810a253d06d28a24d 100644
--- a/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js
+++ b/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js
@@ -181,6 +181,29 @@ approval_settings:
     enabled: true
 `;
 
+export const mockPolicyScopeScanResultManifest = `type: scan_result_policy
+name: policy scope
+description: This policy enforces policy scope
+enabled: true
+rules: []
+actions: []
+policy_scope:
+  compliance_frameworks:
+    - id: 26
+`;
+
+export const mockPolicyScopeScanResultObject = {
+  type: 'scan_result_policy',
+  name: 'policy scope',
+  description: 'This policy enforces policy scope',
+  enabled: true,
+  rules: [],
+  actions: [],
+  policy_scope: {
+    compliance_frameworks: [{ id: 26 }],
+  },
+};
+
 export const mockApprovalSettingsScanResultObject = {
   type: 'scan_result_policy',
   name: 'critical vulnerability CS approvals',
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 48896fb3e1d99a8068f9f53dcc5f414cec2fc6c4..3b8701619a7c919bec6a1435275d1000291a7ffc 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -237,11 +237,6 @@ msgid_plural "%d completed issues"
 msgstr[0] ""
 msgstr[1] ""
 
-msgid "%d compliance framework selected"
-msgid_plural "%d compliance frameworks selected"
-msgstr[0] ""
-msgstr[1] ""
-
 msgid "%d contribution"
 msgid_plural "%d contributions"
 msgstr[0] ""
@@ -4799,9 +4794,6 @@ msgstr ""
 msgid "All environments"
 msgstr ""
 
-msgid "All frameworks selected"
-msgstr ""
-
 msgid "All groups"
 msgstr ""
 
@@ -43133,9 +43125,6 @@ msgstr ""
 msgid "SecurityOrchestration|Choose approver type"
 msgstr ""
 
-msgid "SecurityOrchestration|Choose framework labels"
-msgstr ""
-
 msgid "SecurityOrchestration|Choose specific role"
 msgstr ""
 
@@ -43606,6 +43595,9 @@ msgstr ""
 msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
 msgstr ""
 
+msgid "SecurityOrchestration|compliance frameworks"
+msgstr ""
+
 msgid "SecurityOrchestration|except projects"
 msgstr ""