diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/vulnerability_management/editor_component.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/vulnerability_management/editor_component.vue
index 1ea8ae66564678c316fecc1e6ee3fd6f475b9171..810faa07cdda342eda06c4ba3fd91195cf2ddff7 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/vulnerability_management/editor_component.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/vulnerability_management/editor_component.vue
@@ -1,5 +1,6 @@
 <script>
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { s__, sprintf, n__ } from '~/locale';
 import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import { POLICY_TYPE_COMPONENT_OPTIONS } from 'ee/security_orchestration/components/constants';
 import { extractPolicyContent } from 'ee/security_orchestration/components/utils';
@@ -15,6 +16,7 @@ import {
   EDITOR_MODE_YAML,
   PARSING_ERROR_MESSAGE,
   SECURITY_POLICY_ACTIONS,
+  MAX_ALLOWED_RULES_LENGTH,
 } from '../constants';
 import EditorLayout from '../editor_layout.vue';
 import DimDisableContainer from '../dim_disable_container.vue';
@@ -34,6 +36,9 @@ export default {
     RULES_LABEL,
     ADD_RULE_LABEL,
     ACTIONS_LABEL,
+    exceedingRulesMessage: s__(
+      'SecurityOrchestration|You can add a maximum of %{rulesCount} %{rules}.',
+    ),
   },
   components: {
     GlButton,
@@ -42,6 +47,7 @@ export default {
     ActionSection,
     DimDisableContainer,
   },
+  directives: { GlTooltip: GlTooltipDirective },
   mixins: [glFeatureFlagsMixin()],
   inject: ['namespacePath'],
   props: {
@@ -92,6 +98,18 @@ export default {
       parsingError,
     };
   },
+  computed: {
+    canAddRule() {
+      return this.policy.rules?.length < MAX_ALLOWED_RULES_LENGTH;
+    },
+    addRuleTitle() {
+      const rules = n__('rule', 'rules', this.policy.rules?.length);
+      return sprintf(this.$options.i18n.exceedingRulesMessage, {
+        rulesCount: MAX_ALLOWED_RULES_LENGTH,
+        rules,
+      });
+    },
+  },
   methods: {
     changeEditorMode(mode) {
       this.mode = mode;
@@ -184,9 +202,22 @@ export default {
         />
 
         <div class="security-policies-bg-subtle gl-mb-5 gl-rounded-base gl-p-5">
-          <gl-button variant="link" data-testid="add-rule" @click="addRule">
-            {{ $options.i18n.ADD_RULE_LABEL }}
-          </gl-button>
+          <span
+            v-gl-tooltip="{
+              disabled: canAddRule,
+              title: addRuleTitle,
+            }"
+            data-testid="add-rule-wrapper"
+          >
+            <gl-button
+              variant="link"
+              data-testid="add-rule"
+              :disabled="!canAddRule"
+              @click="addRule"
+            >
+              {{ $options.i18n.ADD_RULE_LABEL }}
+            </gl-button>
+          </span>
         </div>
       </dim-disable-container>
     </template>
diff --git a/ee/app/validators/json_schemas/security_orchestration_policy.json b/ee/app/validators/json_schemas/security_orchestration_policy.json
index f9af0db8a48c7fffe4f2199f6594157ece448366..506d5589530c0efca5cc80d039cc46bd0619ff60 100644
--- a/ee/app/validators/json_schemas/security_orchestration_policy.json
+++ b/ee/app/validators/json_schemas/security_orchestration_policy.json
@@ -67,6 +67,7 @@
           "rules": {
             "description": "Specifies conditions when this policy should be applied.",
             "type": "array",
+            "maxItems": 5,
             "additionalItems": false,
             "items": {
               "type": "object",
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/vulnerability_management/editor_component_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/vulnerability_management/editor_component_spec.js
index 8c562a17f8dadda9ae4d46d02f9269e492f10024..d3dc8753bcc7b1eee765dd2401a6d187f4f5e72f 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/vulnerability_management/editor_component_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/vulnerability_management/editor_component_spec.js
@@ -1,6 +1,7 @@
 import { nextTick } from 'vue';
 import waitForPromises from 'helpers/wait_for_promises';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
 import { DEFAULT_ASSIGNED_POLICY_PROJECT } from 'ee/security_orchestration/constants';
 import EditorComponent from 'ee/security_orchestration/components/policy_editor/vulnerability_management/editor_component.vue';
 import EditorLayout from 'ee/security_orchestration/components/policy_editor/editor_layout.vue';
@@ -25,6 +26,9 @@ describe('EditorComponent', () => {
 
   const factory = ({ propsData = {}, provide = {} } = {}) => {
     wrapper = shallowMountExtended(EditorComponent, {
+      directives: {
+        GlTooltip: createMockDirective('gl-tooltip'),
+      },
       propsData: {
         assignedPolicyProject: DEFAULT_ASSIGNED_POLICY_PROJECT,
         isCreating: false,
@@ -39,11 +43,11 @@ describe('EditorComponent', () => {
     });
   };
 
-  const factoryWithExistingPolicy = () => {
+  const factoryWithExistingPolicy = ({ policy = {} } = {}) => {
     return factory({
       propsData: {
         assignedPolicyProject: ASSIGNED_POLICY_PROJECT,
-        existingPolicy: mockVulnerabilityManagementObject,
+        existingPolicy: { ...mockVulnerabilityManagementObject, ...policy },
         isEditing: true,
       },
     });
@@ -53,6 +57,8 @@ describe('EditorComponent', () => {
   const findRuleSection = () => wrapper.findComponent(RuleSection);
   const findAllRuleSections = () => wrapper.findAllComponents(RuleSection);
   const findAddRuleButton = () => wrapper.findByTestId('add-rule');
+  const findTooltip = () =>
+    getBinding(wrapper.findByTestId('add-rule-wrapper').element, 'gl-tooltip');
   const findActionSection = () => wrapper.findComponent(ActionSection);
 
   beforeEach(() => {
@@ -105,6 +111,20 @@ describe('EditorComponent', () => {
 
       it('shows correct label for add rule button', () => {
         expect(findAddRuleButton().text()).toBe('Add new rule');
+        expect(findAddRuleButton().props('disabled')).toBe(false);
+        expect(findTooltip().value.disabled).toBe(true);
+      });
+
+      it('disables add button when the limit of 5 rules has been reached', () => {
+        const limit = 5;
+        const { id, ...rule } = mockVulnerabilityManagementObject.rules[0];
+        factoryWithExistingPolicy({ policy: { rules: [rule, rule, rule, rule, rule] } });
+        expect(findAllRuleSections()).toHaveLength(limit);
+        expect(findAddRuleButton().props('disabled')).toBe(true);
+        expect(findTooltip().value).toMatchObject({
+          disabled: false,
+          title: 'You can add a maximum of 5 rules.',
+        });
       });
 
       it('removes rule when "remove" event is emitted', async () => {
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a94b5e9cba4d0737e224e29b8a38f6284e8386be..972466893370ac9147d7d212230739a00579c434 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -50546,6 +50546,9 @@ msgstr ""
 msgid "SecurityOrchestration|You already have the maximum %{maximumAllowed} %{policyType} %{instance}."
 msgstr ""
 
+msgid "SecurityOrchestration|You can add a maximum of %{rulesCount} %{rules}."
+msgstr ""
+
 msgid "SecurityOrchestration|You can select this option only once."
 msgstr ""