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 2ea21d9c594a5ff13497e4452d528e01138f768a..a2b07926529a66b1fd962434155e4254acedbb8a 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
@@ -106,6 +106,7 @@ export const RULE_MODE_SCANNERS = {
 };
 
 export const MAX_ALLOWED_RULES_LENGTH = 5;
+export const MAX_ALLOWED_APPROVER_ACTION_LENGTH = 5;
 
 export const PRIMARY_POLICY_KEYS = [
   'type',
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section.vue
index 57c72f167b495066444e3126983aff22150053d4..bc92d3317067636001a93b3e9e707a4699852a19 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section.vue
@@ -1,18 +1,14 @@
 <script>
 import { GlButton } from '@gitlab/ui';
 import { ACTION_AND_LABEL } from '../../constants';
-import { REQUIRE_APPROVAL_TYPE, DISABLED_BOT_MESSAGE_ACTION } from '../lib';
 import ApproverAction from './approver_action.vue';
-import BotMessageAction from './bot_message_action.vue';
 
 export default {
   ACTION_AND_LABEL,
-  DISABLED_BOT_MESSAGE_ACTION,
   name: 'ActionSection',
   components: {
     GlButton,
     ApproverAction,
-    BotMessageAction,
   },
   props: {
     actionIndex: {
@@ -34,20 +30,13 @@ export default {
     },
   },
   computed: {
-    isApproverAction() {
-      return this.initAction.type === REQUIRE_APPROVAL_TYPE;
-    },
     isFirstAction() {
       return this.actionIndex === 0;
     },
   },
   methods: {
     remove() {
-      if (this.isApproverAction) {
-        this.$emit('remove');
-      } else {
-        this.$emit('changed', this.$options.DISABLED_BOT_MESSAGE_ACTION);
-      }
+      this.$emit('remove');
     },
   },
 };
@@ -66,7 +55,6 @@ export default {
     <div class="gl-flex gl-w-full">
       <div class="gl-flex-1">
         <approver-action
-          v-if="isApproverAction"
           :init-action="initAction"
           :errors="errors"
           :existing-approvers="existingApprovers"
@@ -74,7 +62,6 @@ export default {
           @updateApprovers="$emit('updateApprovers', $event)"
           @changed="$emit('changed', $event)"
         />
-        <bot-message-action v-else :init-action="initAction" />
       </div>
       <div class="security-policies-bg-subtle">
         <gl-button
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/bot_message_action.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/bot_message_action.vue
index 448a16c24267b958c3014675fad33bccdd4317b0..2289457b31e4844e5f218d28a024575c59593b89 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/bot_message_action.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/bot_message_action.vue
@@ -3,8 +3,10 @@ import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
 import { helpPagePath } from '~/helpers/help_page_helper';
 import { s__ } from '~/locale';
 import SectionLayout from '../../section_layout.vue';
+import { DISABLED_BOT_MESSAGE_ACTION } from '../lib';
 
 export default {
+  DISABLED_BOT_MESSAGE_ACTION,
   documentationLink: helpPagePath(
     'user/application_security/policies/merge_request_approval_policies',
     {
@@ -24,11 +26,21 @@ export default {
     GlSprintf,
     SectionLayout,
   },
+  methods: {
+    remove() {
+      this.$emit('changed', this.$options.DISABLED_BOT_MESSAGE_ACTION);
+    },
+  },
 };
 </script>
 
 <template>
-  <section-layout :show-remove-button="false">
+  <section-layout
+    class="gl-pr-0 gl-pt-0"
+    content-classes="gl-pt-5"
+    :show-remove-button="true"
+    @remove="remove"
+  >
     <template #content>
       <div class="gl-mt-3 gl-flex-col">
         <gl-sprintf :message="$options.i18n.contentText">
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue
index 031d31f82d6fcb8310ac9db1b9aff8b36ceb07a9..c608974d13d7a0309c3bd372ff85dd7c7f1e134d 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue
@@ -1,5 +1,5 @@
 <script>
-import { isEmpty, uniqBy } from 'lodash';
+import { isEmpty } from 'lodash';
 import { GlAlert, GlEmptyState, GlButton } from '@gitlab/ui';
 import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import { setUrlFragment } from '~/lib/utils/url_utility';
@@ -17,12 +17,14 @@ import {
   ADD_RULE_LABEL,
   RULES_LABEL,
   MAX_ALLOWED_RULES_LENGTH,
+  MAX_ALLOWED_APPROVER_ACTION_LENGTH,
 } from '../constants';
 import EditorLayout from '../editor_layout.vue';
 import DimDisableContainer from '../dim_disable_container.vue';
 import ScanFilterSelector from '../scan_filter_selector.vue';
 import SettingsSection from './settings/settings_section.vue';
 import ActionSection from './action/action_section.vue';
+import BotCommentAction from './action/bot_message_action.vue';
 import RuleSection from './rule/rule_section.vue';
 import FallbackSection from './fallback_section.vue';
 import { CLOSED } from './constants';
@@ -79,9 +81,16 @@ export default {
     settingErrorDescription: s__(
       "SecurityOrchestration|This policy doesn't contain any actions or override project approval settings. You cannot create an empty policy.",
     ),
+    approverActionTooltip: s__(
+      'SecurityOrchestration|Merge request approval policies allow a maximum of 5 approver actions.',
+    ),
+    botActionTooltip: s__(
+      'SecurityOrchestration|Merge request approval policies allow a maximum 1 bot message action.',
+    ),
   },
   components: {
     ActionSection,
+    BotCommentAction,
     DimDisableContainer,
     FallbackSection,
     GlAlert,
@@ -122,6 +131,7 @@ export default {
   },
   mixins: [glFeatureFlagsMixin()],
   inject: [
+    'actionApprovers',
     'disableScanPolicyUpdate',
     'namespaceId',
     'namespacePath',
@@ -167,6 +177,10 @@ export default {
 
     const { policy, hasParsingError } = createPolicyObject(yamlEditorValue);
 
+    const existingApprovers = isEmpty(this.scanResultPolicyApprovers)
+      ? this.actionApprovers
+      : [this.scanResultPolicyApprovers];
+
     return {
       errors: { action: [] },
       invalidBranches: [],
@@ -178,7 +192,7 @@ export default {
         'scan-result-policy-editor',
       ),
       mode: EDITOR_MODE_RULE,
-      existingApprovers: this.scanResultPolicyApprovers,
+      existingApprovers,
       yamlEditorValue,
     };
   },
@@ -193,23 +207,26 @@ export default {
 
       return this.errors;
     },
-    actionsForRuleMode() {
-      const actions = this.policy.actions || [];
+    actions() {
+      const actions = this.policy?.actions || [];
+      const hasBotAction = actions.some(({ type }) => type === BOT_MESSAGE_TYPE);
       // If the yaml does not have a bot message action, then the bot message will be created as if
       // the bot message action exists and is enabled. Thus, we add it into the actions for rule
       // mode so the user can remove it
-      const policiesWithBotMessageAction = uniqBy(
-        [...actions, buildAction(BOT_MESSAGE_TYPE)],
-        'type',
-      );
-      // If the bot message action is disabled, it should not appear in rule mode
-      return policiesWithBotMessageAction.filter(
-        (action) => action.type !== BOT_MESSAGE_TYPE || action.enabled,
-      );
+      if (hasBotAction) {
+        return actions;
+      }
+
+      return [...actions, buildAction(BOT_MESSAGE_TYPE)];
     },
-    availableActionListboxItems() {
-      const usedActionTypes = this.actionsForRuleMode.map((action) => action.type);
-      return ACTION_LISTBOX_ITEMS.filter((item) => !usedActionTypes.includes(item.value));
+    approversActions() {
+      return this.actions
+        .filter(({ type }) => type === REQUIRE_APPROVAL_TYPE)
+        .slice(0, MAX_ALLOWED_APPROVER_ACTION_LENGTH);
+    },
+    botActions() {
+      const botActions = this.actions.filter(({ type }) => type === BOT_MESSAGE_TYPE);
+      return botActions.filter(({ enabled }) => enabled);
     },
     fallbackBehaviorSetting() {
       return this.policy.fallback_behavior?.fail || CLOSED;
@@ -298,42 +315,48 @@ export default {
     },
   },
   methods: {
+    getExistingApprover(index) {
+      return this.existingApprovers[index] || {};
+    },
     ruleHasBranchesProperty(rule) {
       return BRANCHES_KEY in rule;
     },
     addAction(type) {
-      if (type === BOT_MESSAGE_TYPE && this.hasDisabledBotMessageAction) {
-        // If the bot message action is in the yaml and is disabled, then we do not want to add
-        // a new bot message action, but instead enable the existing one
-        this.updateAction(buildAction(BOT_MESSAGE_TYPE));
+      if (type === REQUIRE_APPROVAL_TYPE) {
+        this.addApproverAction();
       } else {
-        const newAction = buildAction(type);
-        this.policy = {
-          ...this.policy,
-          actions: this.policy.actions ? [...this.policy.actions, newAction] : [newAction],
-        };
-        this.updateYamlEditorValue(this.policy);
+        this.addBotAction();
       }
     },
-    removeApproverAction() {
-      const { actions, ...newPolicy } = this.policy;
-      const updatedActions = actions.filter((action) => action.type !== REQUIRE_APPROVAL_TYPE);
-      this.policy = { ...newPolicy, ...(updatedActions.length ? { actions: updatedActions } : {}) };
-      this.updateYamlEditorValue(this.policy);
-      this.updatePolicyApprovers({});
+    addApproverAction() {
+      const lastApproverActionIndex = this.policy.actions.findLastIndex(
+        ({ type }) => type === REQUIRE_APPROVAL_TYPE,
+      );
+      const nextIndex = lastApproverActionIndex + 1;
+      this.policy.actions.splice(nextIndex, 0, buildAction(REQUIRE_APPROVAL_TYPE));
     },
-    updateAction(values) {
-      const actionType = values.type;
-      const actions = this.policy.actions || [];
-      const indexOfActionToUpdate = actions.findIndex((a) => a.type === actionType);
-
-      if (indexOfActionToUpdate >= 0) {
-        actions.splice(indexOfActionToUpdate, 1, values);
+    addBotAction() {
+      if (this.hasDisabledBotMessageAction) {
+        this.updateBotAction(buildAction(BOT_MESSAGE_TYPE));
       } else {
-        actions.push(values);
+        this.policy.actions.push(buildAction(BOT_MESSAGE_TYPE));
       }
+    },
+    removeApproverAction(index) {
+      this.policy.actions?.splice(index, 1);
+      this.updateYamlEditorValue(this.policy);
+      this.updatePolicyApprovers({}, index);
+    },
+    updateAction(values, index) {
+      this.policy.actions.splice(index, 1, values);
+      this.errors.action = [];
+      this.updateYamlEditorValue(this.policy);
+    },
+    updateBotAction(values) {
+      const actions = this.policy.actions || [];
+      const indexOfActionToUpdate = actions.findIndex((a) => a.type === BOT_MESSAGE_TYPE);
 
-      this.policy.actions = actions;
+      actions.splice(indexOfActionToUpdate, 1, values);
       this.errors.action = [];
       this.updateYamlEditorValue(this.policy);
     },
@@ -404,13 +427,14 @@ export default {
         }
       }
     },
-    updatePolicyApprovers(values) {
-      this.existingApprovers = values;
+    updatePolicyApprovers(values, index) {
+      this.existingApprovers[index] = values;
     },
     invalidForRuleMode() {
-      const { actions, rules } = this.policy;
-      const approvalAction = actions?.find((action) => action.type === REQUIRE_APPROVAL_TYPE);
-      const invalidApprovers = approversOutOfSync(approvalAction, this.existingApprovers);
+      const { rules } = this.policy;
+      const invalidApprovers = this.existingApprovers.some((existingApprovers, index) =>
+        approversOutOfSync(this.approversActions[index], existingApprovers),
+      );
 
       return (
         invalidApprovers ||
@@ -423,6 +447,20 @@ export default {
         invalidVulnerabilityAttributes(rules)
       );
     },
+    shouldDisableActionSelector(filter) {
+      if (filter === BOT_MESSAGE_TYPE) {
+        return this.botActions.length > 0;
+      }
+
+      return this.approversActions.length >= MAX_ALLOWED_APPROVER_ACTION_LENGTH;
+    },
+    customFilterSelectorTooltip(filter) {
+      if (filter.value === BOT_MESSAGE_TYPE) {
+        return this.$options.i18n.botActionTooltip;
+      }
+
+      return this.$options.i18n.approverActionTooltip;
+    },
   },
 };
 </script>
@@ -488,26 +526,35 @@ export default {
         </template>
 
         <action-section
-          v-for="(action, index) in actionsForRuleMode"
-          :key="action.id"
+          v-for="(action, index) in approversActions"
+          :key="`${action.id}_${index}`"
           :data-testid="`action-${index}`"
           class="gl-mb-4"
           :action-index="index"
           :init-action="action"
           :errors="actionError.action"
-          :existing-approvers="existingApprovers"
+          :existing-approvers="getExistingApprover(index)"
           @error="handleParsingError"
-          @updateApprovers="updatePolicyApprovers"
-          @changed="updateAction"
-          @remove="removeApproverAction"
+          @updateApprovers="updatePolicyApprovers($event, index)"
+          @changed="updateAction($event, index)"
+          @remove="removeApproverAction(index)"
+        />
+
+        <bot-comment-action
+          v-for="action in botActions"
+          :key="action.id"
+          class="gl-mb-4"
+          :init-action="action"
+          @changed="updateBotAction($event)"
         />
 
         <scan-filter-selector
-          v-if="availableActionListboxItems.length"
           class="gl-w-full"
           :button-text="$options.i18n.ADD_ACTION_LABEL"
           :header="$options.i18n.filterHeaderText"
-          :filters="availableActionListboxItems"
+          :custom-filter-tooltip="customFilterSelectorTooltip"
+          :should-disable-filter="shouldDisableActionSelector"
+          :filters="$options.ACTION_LISTBOX_ITEMS"
           @select="addAction"
         />
       </dim-disable-container>
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 3169b66506ead3e2adee7a2d535c25fce8caa1d0..f2d5515acf5750d0a4128d4724c27dfa3949502c 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
@@ -1,5 +1,5 @@
 import { safeLoad } from 'js-yaml';
-import { isBoolean, isEqual, uniqBy } from 'lodash';
+import { isBoolean, isEqual } from 'lodash';
 import { addIdsToPolicy, hasInvalidKey, isValidPolicy } from '../../utils';
 import { PRIMARY_POLICY_KEYS } from '../../constants';
 import { OPEN, CLOSED } from '../constants';
@@ -63,7 +63,7 @@ export const fromYaml = ({ manifest, validateRuleMode = false }) => {
         'enabled',
       ];
 
-      const { actions, approval_settings: settings = {}, fallback_behavior: fallback } = policy;
+      const { approval_settings: settings = {}, fallback_behavior: fallback } = policy;
 
       // Temporary workaround to allow the rule builder to load with wrongly persisted settings
       const hasInvalidApprovalSettings = hasInvalidKey(settings, [
@@ -77,16 +77,11 @@ export const fromYaml = ({ manifest, validateRuleMode = false }) => {
           )
         : false;
 
-      const hasInvalidActions =
-        actions?.length > 2 ||
-        (actions?.length && actions.length !== uniqBy(actions, 'type').length);
-
       const hasInvalidFallbackBehavior = fallback && ![OPEN, CLOSED].includes(fallback.fail);
 
       return isValidPolicy({ policy, primaryKeys, rulesKeys, actionsKeys }) &&
         !hasInvalidApprovalSettings &&
         !hasInvalidSettingStructure &&
-        !hasInvalidActions &&
         !hasInvalidFallbackBehavior
         ? policy
         : { error: true };
diff --git a/ee/app/assets/javascripts/security_orchestration/policy_editor.js b/ee/app/assets/javascripts/security_orchestration/policy_editor.js
index cb4fb73b3730cf76b364a9e8fc8ebc30316cb0f4..dbcb266203f6f1ed3a154fe2a190620d5508c755 100644
--- a/ee/app/assets/javascripts/security_orchestration/policy_editor.js
+++ b/ee/app/assets/javascripts/security_orchestration/policy_editor.js
@@ -31,6 +31,7 @@ export default (el, namespaceType) => {
     scanResultApprovers,
     softwareLicenses,
     timezones,
+    actionApprovers,
     maxScanExecutionPolicyActions,
   } = el.dataset;
 
@@ -54,6 +55,7 @@ export default (el, namespaceType) => {
   }
 
   let scanResultPolicyApprovers;
+  let parsedActionApprovers;
 
   try {
     scanResultPolicyApprovers = decomposeApprovers(
@@ -65,6 +67,12 @@ export default (el, namespaceType) => {
     scanResultPolicyApprovers = {};
   }
 
+  try {
+    parsedActionApprovers = JSON.parse(actionApprovers);
+  } catch {
+    parsedActionApprovers = [];
+  }
+
   try {
     parsedTimezones = JSON.parse(timezones);
   } catch {
@@ -80,6 +88,7 @@ export default (el, namespaceType) => {
     el,
     apolloProvider,
     provide: {
+      actionApprovers: parsedActionApprovers,
       createAgentHelpPath,
       disableScanPolicyUpdate: parseBoolean(disableScanPolicyUpdate),
       globalGroupApproversEnabled: parseBoolean(globalGroupApproversEnabled),
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_spec.js
index a55c841a701066ac74975f030599ac76cc673994..1a3e075d976493a37939c1b3a0c6a87218a6a76f 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_spec.js
@@ -2,11 +2,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 import ActionSection from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_section.vue';
 import ApproverAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue';
 import BotCommentAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/bot_message_action.vue';
-import {
-  BOT_MESSAGE_TYPE,
-  REQUIRE_APPROVAL_TYPE,
-  DISABLED_BOT_MESSAGE_ACTION,
-} from 'ee/security_orchestration/components/policy_editor/scan_result/lib';
+import { REQUIRE_APPROVAL_TYPE } from 'ee/security_orchestration/components/policy_editor/scan_result/lib';
 
 describe('ActionSection', () => {
   let wrapper;
@@ -72,21 +68,4 @@ describe('ActionSection', () => {
       });
     });
   });
-
-  describe('Bot Comment Action', () => {
-    it('renders a bot comment action for that type of action', () => {
-      factory({ props: { initAction: { type: BOT_MESSAGE_TYPE } } });
-      expect(findBotCommentAction().exists()).toBe(true);
-      expect(findApproverAction().exists()).toBe(false);
-      expect(findActionSeperator().exists()).toBe(false);
-    });
-
-    it('emits "changed" on removal', () => {
-      factory({ props: { initAction: { type: BOT_MESSAGE_TYPE } } });
-      findRemoveButton().vm.$emit('click');
-      expect(wrapper.emitted('changed')).toEqual([
-        [expect.objectContaining(DISABLED_BOT_MESSAGE_ACTION)],
-      ]);
-    });
-  });
 });
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/bot_message_action_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/bot_message_action_spec.js
index 82ac7a9e9c82ced653f6014be866b5ef508f7688..d7567bfc29a0f8a9fb99aa0c6bd1a891b2fb2992 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/bot_message_action_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/bot_message_action_spec.js
@@ -2,6 +2,7 @@ import { GlLink, GlSprintf } from '@gitlab/ui';
 import { shallowMount } from '@vue/test-utils';
 import SectionLayout from 'ee/security_orchestration/components/policy_editor/section_layout.vue';
 import BotCommentAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/bot_message_action.vue';
+import { DISABLED_BOT_MESSAGE_ACTION } from 'ee/security_orchestration/components/policy_editor/scan_result/lib';
 
 describe('BotCommentAction', () => {
   let wrapper;
@@ -29,4 +30,11 @@ describe('BotCommentAction', () => {
       '/help/user/application_security/policies/merge_request_approval_policies#example-bot-messages',
     );
   });
+
+  it('emits changed event when action is removed', () => {
+    factory();
+    findSectionLayout().vm.$emit('remove');
+
+    expect(wrapper.emitted('changed')).toEqual([[DISABLED_BOT_MESSAGE_ACTION]]);
+  });
 });
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js
index 1d8f54e54905b94ed548eeb7536520d707b95ffc..998a2dc283c9c1a918064a355f359c944b84eead 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js
@@ -14,6 +14,7 @@ import {
 } from 'ee/security_orchestration/components/policy_editor/scan_result/constants';
 import ScanFilterSelector from 'ee/security_orchestration/components/policy_editor/scan_filter_selector.vue';
 import EditorLayout from 'ee/security_orchestration/components/policy_editor/editor_layout.vue';
+import BotCommentAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/bot_message_action.vue';
 import {
   ACTION_LISTBOX_ITEMS,
   BLOCK_GROUP_BRANCH_MODIFICATION,
@@ -36,6 +37,7 @@ import {
 import {
   mockDefaultBranchesScanResultManifest,
   mockDefaultBranchesScanResultObject,
+  mockDefaultBranchesScanResultObjectWithoutBotAction,
   mockDeprecatedScanResultManifest,
   mockDeprecatedScanResultObject,
 } from 'ee_jest/security_orchestration/mocks/mock_scan_result_policy_data';
@@ -109,6 +111,7 @@ describe('EditorComponent', () => {
         ...propsData,
       },
       provide: {
+        actionApprovers: [],
         disableScanPolicyUpdate: false,
         policyEditorEmptyStateSvgPath,
         namespaceId: 1,
@@ -155,6 +158,8 @@ describe('EditorComponent', () => {
   const findSettingsSection = () => wrapper.findComponent(SettingsSection);
   const findEmptyActionsAlert = () => wrapper.findByTestId('empty-actions-alert');
   const findScanFilterSelector = () => wrapper.findComponent(ScanFilterSelector);
+  const findBotCommentAction = () => wrapper.findComponent(BotCommentAction);
+  const findBotCommentActions = () => wrapper.findAllComponents(BotCommentAction);
 
   const verifiesParsingError = () => {
     expect(findPolicyEditorLayout().props('hasParsingError')).toBe(true);
@@ -221,8 +226,10 @@ describe('EditorComponent', () => {
         expect(findPolicyEditorLayout().props('yamlEditorValue')).toBe(
           mockDefaultBranchesScanResultManifest,
         );
+
         expect(findAllRuleSections()).toHaveLength(1);
-        expect(findAllActionSections()).toHaveLength(2);
+        expect(findAllActionSections()).toHaveLength(1);
+        expect(findBotCommentActions()).toHaveLength(1);
       });
 
       it('displays a scan result policy', () => {
@@ -232,7 +239,8 @@ describe('EditorComponent', () => {
           mockDeprecatedScanResultManifest,
         );
         expect(findAllRuleSections()).toHaveLength(1);
-        expect(findAllActionSections()).toHaveLength(2);
+        expect(findAllActionSections()).toHaveLength(1);
+        expect(findBotCommentActions()).toHaveLength(1);
       });
     });
   });
@@ -327,7 +335,8 @@ describe('EditorComponent', () => {
           it('displays the approver action and the add action button on the group-level', () => {
             factory({ provide: { namespaceType } });
             expect(findActionSection().exists()).toBe(true);
-            expect(findAllActionSections()).toHaveLength(2);
+            expect(findAllActionSections()).toHaveLength(1);
+            expect(findBotCommentActions()).toHaveLength(1);
           });
         });
 
@@ -344,28 +353,37 @@ describe('EditorComponent', () => {
           });
 
           it('displays a bot message action section if there is no bot message action in the policy', () => {
-            factoryWithExistingPolicy({ policy: mockDefaultBranchesScanResultObject });
-            const actionSections = findAllActionSections();
-            expect(actionSections).toHaveLength(2);
-            expect(actionSections.at(1).props('initAction')).toEqual(
-              expect.objectContaining({ type: BOT_MESSAGE_TYPE, enabled: true }),
-            );
+            factoryWithExistingPolicy({
+              policy: mockDefaultBranchesScanResultObjectWithoutBotAction,
+            });
+            expect(findBotCommentActions()).toHaveLength(1);
           });
         });
       });
 
       describe('add', () => {
-        it('hides the scan filter selector by default, when all action types are used', () => {
+        it('always display rule selector with approver option, when all bot message is selected', () => {
           factoryWithExistingPolicy({ policy: mockDefaultBranchesScanResultObject });
-          expect(findScanFilterSelector().exists()).toBe(false);
+          expect(findScanFilterSelector().exists()).toBe(true);
+          expect(
+            findScanFilterSelector().props('customFilterTooltip')({ value: BOT_MESSAGE_TYPE }),
+          ).toBe('Merge request approval policies allow a maximum 1 bot message action.');
+          expect(findScanFilterSelector().props('filters')).toEqual([
+            { value: REQUIRE_APPROVAL_TYPE, text: 'Require Approvers' },
+            { value: BOT_MESSAGE_TYPE, text: 'Send bot message' },
+          ]);
         });
 
         it('shows the scan filter selector if there are action types not shown', async () => {
           factoryWithExistingPolicy({ policy: mockDefaultBranchesScanResultObject });
           await findAllActionSections().at(0).vm.$emit('remove');
           expect(findScanFilterSelector().exists()).toBe(true);
+          expect(
+            findScanFilterSelector().props('customFilterTooltip')({ value: REQUIRE_APPROVAL_TYPE }),
+          ).toBe('Merge request approval policies allow a maximum of 5 approver actions.');
           expect(findScanFilterSelector().props('filters')).toEqual([
             { text: 'Require Approvers', value: REQUIRE_APPROVAL_TYPE },
+            { text: 'Send bot message', value: BOT_MESSAGE_TYPE },
           ]);
         });
 
@@ -381,20 +399,59 @@ describe('EditorComponent', () => {
             expect.objectContaining(disabledAction),
           ]);
           await findScanFilterSelector().vm.$emit('select', BOT_MESSAGE_TYPE);
-          expect(findAllActionSections()).toHaveLength(1);
+          expect(findAllActionSections()).toHaveLength(0);
+          expect(findBotCommentActions()).toHaveLength(1);
           const { id, ...action } = buildBotMessageAction();
           expect(findPolicyEditorLayout().props('policy').actions).toEqual([
             expect.objectContaining(action),
           ]);
         });
+
+        it('adds multiple approval rules', async () => {
+          factoryWithExistingPolicy({ policy: mockDefaultBranchesScanResultObject });
+
+          expect(findAllActionSections()).toHaveLength(1);
+          expect(findBotCommentActions()).toHaveLength(1);
+
+          await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+
+          expect(findAllActionSections()).toHaveLength(2);
+          expect(findBotCommentActions()).toHaveLength(1);
+
+          await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+
+          expect(findAllActionSections()).toHaveLength(3);
+          expect(findBotCommentActions()).toHaveLength(1);
+        });
+
+        it('add maximum of 5 approval actions', async () => {
+          factoryWithExistingPolicy({ policy: mockDefaultBranchesScanResultObject });
+
+          expect(findAllActionSections()).toHaveLength(1);
+
+          await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+          expect(findAllActionSections()).toHaveLength(2);
+
+          await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+          expect(findAllActionSections()).toHaveLength(3);
+
+          await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+          expect(findAllActionSections()).toHaveLength(4);
+
+          await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+          expect(findAllActionSections()).toHaveLength(5);
+
+          await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+          expect(findAllActionSections()).toHaveLength(5);
+        });
       });
 
       describe('remove', () => {
         it('removes the approver action', async () => {
           factory();
-          expect(findAllActionSections()).toHaveLength(2);
-          await findActionSection().vm.$emit('remove');
           expect(findAllActionSections()).toHaveLength(1);
+          await findActionSection().vm.$emit('remove');
+          expect(findAllActionSections()).toHaveLength(0);
           expect(findPolicyEditorLayout().props('policy').actions).not.toContainEqual(
             buildApprovalAction(),
           );
@@ -402,9 +459,11 @@ describe('EditorComponent', () => {
 
         it('disables the bot message action', async () => {
           factory();
-          expect(findAllActionSections()).toHaveLength(2);
-          await findActionSection().vm.$emit('changed', DISABLED_BOT_MESSAGE_ACTION);
           expect(findAllActionSections()).toHaveLength(1);
+          expect(findBotCommentActions()).toHaveLength(1);
+          await findBotCommentAction().vm.$emit('changed', DISABLED_BOT_MESSAGE_ACTION);
+          expect(findAllActionSections()).toHaveLength(1);
+          expect(findBotCommentActions()).toHaveLength(0);
           expect(findPolicyEditorLayout().props('policy').actions).toContainEqual(
             DISABLED_BOT_MESSAGE_ACTION,
           );
@@ -418,9 +477,10 @@ describe('EditorComponent', () => {
           );
           await findAllActionSections().at(0).vm.$emit('remove');
           await findScanFilterSelector().vm.$emit('select', REQUIRE_APPROVAL_TYPE);
+
           expect(removeIdsFromPolicy(findPolicyEditorLayout().props('policy')).actions).toEqual([
-            { type: BOT_MESSAGE_TYPE, enabled: true },
             { approvals_required: 1, type: REQUIRE_APPROVAL_TYPE },
+            { type: BOT_MESSAGE_TYPE, enabled: true },
           ]);
           expect(findActionSection().props('existingApprovers')).toEqual({});
         });
@@ -428,7 +488,12 @@ describe('EditorComponent', () => {
 
       describe('update', () => {
         beforeEach(() => {
-          factory();
+          factory({
+            provide: {
+              scanResultPolicyApprovers: {},
+              actionApprovers: [{ role: ['owner'] }],
+            },
+          });
         });
 
         it('updates policy action when edited', async () => {
@@ -445,12 +510,9 @@ describe('EditorComponent', () => {
         it('updates the policy approvers', async () => {
           const newApprover = ['owner'];
 
-          await findActionSection().vm.$emit('updateApprovers', {
-            ...scanResultPolicyApprovers,
-            role: newApprover,
-          });
+          await findActionSection().vm.$emit('updateApprovers', { role: newApprover });
 
-          expect(findActionSection().props('existingApprovers')).toMatchObject({
+          expect(findActionSection().props('existingApprovers')).toEqual({
             role: newApprover,
           });
         });
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 093eee1f5d6854209a8c49bf467b00af01537741..337fed7ee702d360235c84aa4920317c04c9f6fe 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
@@ -12,12 +12,10 @@ import {
   mockGroupApprovalSettingsScanResultObject,
   mockApprovalSettingsPermittedInvalidScanResultManifest,
   mockApprovalSettingsPermittedInvalidScanResultObject,
-  mockPolicyScopeScanResultManifest,
-  mockPolicyScopeScanResultObject,
   mockProjectFallbackClosedScanResultManifest,
   mockProjectFallbackClosedScanResultObject,
-  tooManyActionsScanResultManifest,
-  duplicateActionsScanResultManifest,
+  multipleApproverActionsScanResultManifest,
+  multipleApproverActionsScanResultObject,
   zeroActionsScanResultManifest,
   zeroActionsScanResultObject,
   mockFallbackInvalidScanResultManifest,
@@ -43,7 +41,7 @@ describe('fromYaml', () => {
       ${'without actions'}                                                | ${zeroActionsScanResultManifest}                          | ${zeroActionsScanResultObject}
       ${'with fail: closed'}                                              | ${mockProjectFallbackClosedScanResultManifest}            | ${mockProjectFallbackClosedScanResultObject}
       ${'with `approval_settings` containing permitted invalid settings'} | ${mockApprovalSettingsPermittedInvalidScanResultManifest} | ${mockApprovalSettingsPermittedInvalidScanResultObject}
-      ${'with `policy_scope` by default'}                                 | ${mockPolicyScopeScanResultManifest}                      | ${mockPolicyScopeScanResultObject}
+      ${'with multiple actions'}                                          | ${multipleApproverActionsScanResultManifest}              | ${multipleApproverActionsScanResultObject}
     `('returns the policy object for a manifest $title', ({ manifest, output }) => {
       expect(fromYaml({ manifest, validateRuleMode: true })).toStrictEqual(output);
     });
@@ -53,8 +51,6 @@ describe('fromYaml', () => {
     it.each`
       title                              | manifest
       ${'unsupported fallback behavior'} | ${mockFallbackInvalidScanResultManifest}
-      ${'more than two actions'}         | ${tooManyActionsScanResultManifest}
-      ${'duplicate action types'}        | ${duplicateActionsScanResultManifest}
       ${'an unsupported attribute'}      | ${unsupportedManifest}
       ${'colliding self excluded keys'}  | ${collidingKeysScanResultManifest}
     `('returns the error object for a policy with $title', ({ manifest }) => {
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 01769895bc1afac97ae4df528d7cfe208c60a20a..0be655310abcae895344e0ce3ffe9ca540429a1a 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
@@ -69,6 +69,18 @@ export const mockDefaultBranchesScanResultObject = {
   },
 };
 
+export const mockDefaultBranchesScanResultObjectWithoutBotAction = {
+  ...mockDefaultBranchesScanResultObject,
+  actions: [
+    {
+      type: 'require_approval',
+      approvals_required: 1,
+      user_approvers: ['the.one'],
+      id: actionId,
+    },
+  ],
+};
+
 export const mockDeprecatedScanResultManifest = `type: scan_result_policy
 name: critical vulnerability CS approvals
 description: This policy enforces critical vulnerability CS approvals
@@ -126,22 +138,39 @@ export const zeroActionsScanResultObject = {
   ],
 };
 
-export const tooManyActionsScanResultManifest = zeroActionsScanResultManifest.concat(`
+export const multipleApproverActionsScanResultManifest = zeroActionsScanResultManifest.concat(`
 actions:
   - type: require_approval
     approvals_required: 1
   - type: send_bot_message
     enabled: true
-  - type: other_type
-`);
-
-export const duplicateActionsScanResultManifest = zeroActionsScanResultManifest.concat(`actions:
-  - type: require_approval
-    approvals_required: 1
   - type: require_approval
     approvals_required: 1
 `);
 
+export const multipleApproverActionsScanResultObject = {
+  type: 'approval_policy',
+  name: 'critical vulnerability CS approvals',
+  description: 'This policy enforces critical vulnerability CS approvals',
+  enabled: true,
+  rules: [
+    {
+      type: 'scan_finding',
+      branches: [],
+      scanners: ['container_scanning'],
+      vulnerabilities_allowed: 1,
+      severity_levels: ['critical'],
+      vulnerability_states: ['newly_detected'],
+      id: ruleId,
+    },
+  ],
+  actions: [
+    { type: 'require_approval', approvals_required: 1, id: actionId },
+    { type: 'send_bot_message', enabled: true, id: actionId },
+    { type: 'require_approval', approvals_required: 1, id: actionId },
+  ],
+};
+
 export const enabledSendBotMessageActionScanResultManifest = zeroActionsScanResultManifest.concat(`
 actions:
   - type: send_bot_message
diff --git a/ee/spec/frontend_integration/security_orchestration/policy_editor/mocks/mocks.js b/ee/spec/frontend_integration/security_orchestration/policy_editor/mocks/mocks.js
index 482562eae64bd6f55247ccb15d239e58972db140..8ab094fd8568a6990989eeacce0838e4c126d210 100644
--- a/ee/spec/frontend_integration/security_orchestration/policy_editor/mocks/mocks.js
+++ b/ee/spec/frontend_integration/security_orchestration/policy_editor/mocks/mocks.js
@@ -1,6 +1,7 @@
 import { NAMESPACE_TYPES } from 'ee/security_orchestration/constants';
 
 export const DEFAULT_PROVIDE = {
+  actionApprovers: [],
   disableScanPolicyUpdate: false,
   disableSecurityPolicyProject: false,
   policyEditorEmptyStateSvgPath: 'path/to/svg',
diff --git a/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js b/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js
index 7805007ff294e232b58a2d2ebea0399044a24b65..939c1aeb311940449a015e77746250835c4eaddc 100644
--- a/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js
+++ b/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js
@@ -49,10 +49,6 @@ describe('Scan result policy actions', () => {
       .mockReturnValue(POLICY_TYPE_COMPONENT_OPTIONS.approval.urlParameter);
   });
 
-  afterEach(() => {
-    window.gon = {};
-  });
-
   const findApprovalsInput = () => wrapper.findByTestId('approvals-required-input');
   const findAvailableTypeListBox = () => wrapper.findByTestId('available-types');
   const findApproverAction = () => wrapper.findComponent(ApproverAction);
@@ -121,7 +117,7 @@ describe('Scan result policy actions', () => {
 
   describe('groups', () => {
     beforeEach(() => {
-      createWrapper({ provide: { existingPolicy: null, namespaceType: 'group' } });
+      createWrapper({ provide: { namespaceType: 'group', actionApprovers: [] } });
     });
 
     it('selects group approvers', async () => {
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d318cf7f47ca3f66800e9cb5ad8475108904a766..ffd449a9f6e9506ea82da5b27cf3479da92cb4ff 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -49802,6 +49802,12 @@ msgstr ""
 msgid "SecurityOrchestration|Merge request approval"
 msgstr ""
 
+msgid "SecurityOrchestration|Merge request approval policies allow a maximum 1 bot message action."
+msgstr ""
+
+msgid "SecurityOrchestration|Merge request approval policies allow a maximum of 5 approver actions."
+msgstr ""
+
 msgid "SecurityOrchestration|Merge request approval policies can only be created by project owners."
 msgstr ""