diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts
index 20da46b4a3cf9..dd04d324d3739 100644
--- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts
@@ -74,12 +74,6 @@ const DEFAULT_INDEX_PATTERNS = ['index-1-*', 'index-2-*'];
 const TAGS = ['cypress-tag-1', 'cypress-tag-2'];
 const OVERWRITE_INDEX_PATTERNS = ['overwrite-index-1-*', 'overwrite-index-2-*'];
 
-const customRule = {
-  ...getNewRule(),
-  index: DEFAULT_INDEX_PATTERNS,
-  name: RULE_NAME,
-};
-
 const expectedNumberOfCustomRulesToBeEdited = 6;
 const expectedNumberOfMachineLearningRulesToBeEdited = 1;
 const numberOfRulesPerPage = 5;
@@ -92,7 +86,14 @@ describe('Detection rules, bulk edit', () => {
   beforeEach(() => {
     deleteAlertsAndRules();
     esArchiverResetKibana();
-    createCustomRule(customRule, '1');
+    createCustomRule(
+      {
+        ...getNewRule(),
+        name: RULE_NAME,
+        dataSource: { index: DEFAULT_INDEX_PATTERNS, type: 'indexPatterns' },
+      },
+      '1'
+    );
     createCustomRule(getExistingRule(), '2');
     createCustomRule(getNewOverrideRule(), '3');
     createCustomRule(getNewThresholdRule(), '4');
diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts
index 92bd07b8a24ba..ba886993c7433 100644
--- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts
@@ -295,10 +295,13 @@ describe('Custom query rules', () => {
     });
 
     context('Edition', () => {
-      const expectedEditedtags = getEditedRule().tags.join('');
+      const rule = getEditedRule();
+      const expectedEditedtags = rule.tags.join('');
       const expectedEditedIndexPatterns =
-        getEditedRule().index && getEditedRule().index.length
-          ? getEditedRule().index
+        rule.dataSource.type === 'indexPatterns' &&
+        rule.dataSource.index &&
+        rule.dataSource.index.length
+          ? rule.dataSource.index
           : getIndexPatterns();
 
       before(() => {
@@ -325,27 +328,32 @@ describe('Custom query rules', () => {
       });
 
       it('Allows a rule to be edited', () => {
+        const existingRule = getExistingRule();
+
         editFirstRule();
 
         // expect define step to populate
-        cy.get(CUSTOM_QUERY_INPUT).should('have.value', getExistingRule().customQuery);
-        if (getExistingRule().index && getExistingRule().index.length > 0) {
-          cy.get(DEFINE_INDEX_INPUT).should('have.text', getExistingRule().index.join(''));
+        cy.get(CUSTOM_QUERY_INPUT).should('have.value', existingRule.customQuery);
+        if (
+          existingRule.dataSource.type === 'indexPatterns' &&
+          existingRule.dataSource.index.length > 0
+        ) {
+          cy.get(DEFINE_INDEX_INPUT).should('have.text', existingRule.dataSource.index.join(''));
         }
 
         goToAboutStepTab();
 
         // expect about step to populate
-        cy.get(RULE_NAME_INPUT).invoke('val').should('eql', getExistingRule().name);
-        cy.get(RULE_DESCRIPTION_INPUT).should('have.text', getExistingRule().description);
-        cy.get(TAGS_FIELD).should('have.text', getExistingRule().tags.join(''));
-        cy.get(SEVERITY_DROPDOWN).should('have.text', getExistingRule().severity);
-        cy.get(DEFAULT_RISK_SCORE_INPUT).invoke('val').should('eql', getExistingRule().riskScore);
+        cy.get(RULE_NAME_INPUT).invoke('val').should('eql', existingRule.name);
+        cy.get(RULE_DESCRIPTION_INPUT).should('have.text', existingRule.description);
+        cy.get(TAGS_FIELD).should('have.text', existingRule.tags.join(''));
+        cy.get(SEVERITY_DROPDOWN).should('have.text', existingRule.severity);
+        cy.get(DEFAULT_RISK_SCORE_INPUT).invoke('val').should('eql', existingRule.riskScore);
 
         goToScheduleStepTab();
 
         // expect schedule step to populate
-        const interval = getExistingRule().interval;
+        const interval = existingRule.interval;
         const intervalParts = interval != null && interval.match(/[0-9]+|[a-zA-Z]+/g);
         if (intervalParts) {
           const [amount, unit] = intervalParts;
@@ -381,7 +389,7 @@ describe('Custom query rules', () => {
         cy.wait('@getRule').then(({ response }) => {
           cy.wrap(response?.statusCode).should('eql', 200);
           // ensure that editing rule does not modify max_signals
-          cy.wrap(response?.body.max_signals).should('eql', getExistingRule().maxSignals);
+          cy.wrap(response?.body.max_signals).should('eql', existingRule.maxSignals);
         });
 
         cy.get(RULE_NAME_HEADER).should('contain', `${getEditedRule().name}`);
@@ -396,7 +404,7 @@ describe('Custom query rules', () => {
         cy.get(DEFINITION_DETAILS).within(() => {
           getDetails(INDEX_PATTERNS_DETAILS).should(
             'have.text',
-            expectedEditedIndexPatterns.join('')
+            expectedEditedIndexPatterns?.join('')
           );
           getDetails(CUSTOM_QUERY_DETAILS).should('have.text', getEditedRule().customQuery);
           getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query');
diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule_data_view.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule_data_view.spec.ts
new file mode 100644
index 0000000000000..77a4ae274e6e4
--- /dev/null
+++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule_data_view.spec.ts
@@ -0,0 +1,158 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { formatMitreAttackDescription } from '../../helpers/rules';
+import { getDataViewRule } from '../../objects/rule';
+import { ALERT_GRID_CELL, NUMBER_OF_ALERTS } from '../../screens/alerts';
+
+import {
+  CUSTOM_RULES_BTN,
+  RISK_SCORE,
+  RULE_NAME,
+  RULES_ROW,
+  RULES_TABLE,
+  RULE_SWITCH,
+  SEVERITY,
+} from '../../screens/alerts_detection_rules';
+
+import {
+  ADDITIONAL_LOOK_BACK_DETAILS,
+  ABOUT_DETAILS,
+  ABOUT_INVESTIGATION_NOTES,
+  ABOUT_RULE_DESCRIPTION,
+  CUSTOM_QUERY_DETAILS,
+  DEFINITION_DETAILS,
+  FALSE_POSITIVES_DETAILS,
+  removeExternalLinkText,
+  INDEX_PATTERNS_DETAILS,
+  INVESTIGATION_NOTES_MARKDOWN,
+  INVESTIGATION_NOTES_TOGGLE,
+  MITRE_ATTACK_DETAILS,
+  REFERENCE_URLS_DETAILS,
+  RISK_SCORE_DETAILS,
+  RULE_NAME_HEADER,
+  RULE_TYPE_DETAILS,
+  RUNS_EVERY_DETAILS,
+  SCHEDULE_DETAILS,
+  SEVERITY_DETAILS,
+  TAGS_DETAILS,
+  TIMELINE_TEMPLATE_DETAILS,
+  DATA_VIEW_DETAILS,
+} from '../../screens/rule_details';
+
+import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
+import { createTimeline } from '../../tasks/api_calls/timelines';
+import { postDataView } from '../../tasks/common';
+import {
+  createAndEnableRule,
+  fillAboutRuleAndContinue,
+  fillDefineCustomRuleWithImportedQueryAndContinue,
+  fillScheduleRuleAndContinue,
+  waitForAlertsToPopulate,
+  waitForTheRuleToBeExecuted,
+} from '../../tasks/create_new_rule';
+
+import { esArchiverResetKibana } from '../../tasks/es_archiver';
+import { login, visit } from '../../tasks/login';
+import { getDetails } from '../../tasks/rule_details';
+
+import { RULE_CREATION } from '../../urls/navigation';
+
+describe('Custom query rules', () => {
+  before(() => {
+    login();
+  });
+
+  describe('Custom detection rules creation with data views', () => {
+    const rule = getDataViewRule();
+    const expectedUrls = rule.referenceUrls.join('');
+    const expectedFalsePositives = rule.falsePositivesExamples.join('');
+    const expectedTags = rule.tags.join('');
+    const expectedMitre = formatMitreAttackDescription(rule.mitre);
+    const expectedNumberOfRules = 1;
+
+    beforeEach(() => {
+      /* We don't call cleanKibana method on the before hook, instead we call esArchiverReseKibana on the before each. This is because we 
+      are creating a data view we'll use after and cleanKibana does not delete all the data views created, esArchiverReseKibana does.
+      We don't use esArchiverReseKibana in all the tests because is a time-consuming method and we don't need to perform an exhaustive 
+      cleaning in all the other tests. */
+      esArchiverResetKibana();
+      createTimeline(rule.timeline).then((response) => {
+        cy.wrap({
+          ...rule,
+          timeline: {
+            ...rule.timeline,
+            id: response.body.data.persistTimeline.timeline.savedObjectId,
+          },
+        }).as('rule');
+      });
+      if (rule.dataSource.type === 'dataView') {
+        postDataView(rule.dataSource.dataView);
+      }
+    });
+
+    it('Creates and enables a new rule', function () {
+      visit(RULE_CREATION);
+      fillDefineCustomRuleWithImportedQueryAndContinue(this.rule);
+      fillAboutRuleAndContinue(this.rule);
+      fillScheduleRuleAndContinue(this.rule);
+      createAndEnableRule();
+
+      cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
+
+      cy.get(RULES_TABLE).find(RULES_ROW).should('have.length', expectedNumberOfRules);
+      cy.get(RULE_NAME).should('have.text', this.rule.name);
+      cy.get(RISK_SCORE).should('have.text', this.rule.riskScore);
+      cy.get(SEVERITY).should('have.text', this.rule.severity);
+      cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');
+
+      goToRuleDetails();
+
+      cy.get(RULE_NAME_HEADER).should('contain', `${this.rule.name}`);
+      cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', this.rule.description);
+      cy.get(ABOUT_DETAILS).within(() => {
+        getDetails(SEVERITY_DETAILS).should('have.text', this.rule.severity);
+        getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore);
+        getDetails(REFERENCE_URLS_DETAILS).should((details) => {
+          expect(removeExternalLinkText(details.text())).equal(expectedUrls);
+        });
+        getDetails(FALSE_POSITIVES_DETAILS).should('have.text', expectedFalsePositives);
+        getDetails(MITRE_ATTACK_DETAILS).should((mitre) => {
+          expect(removeExternalLinkText(mitre.text())).equal(expectedMitre);
+        });
+        getDetails(TAGS_DETAILS).should('have.text', expectedTags);
+      });
+      cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true });
+      cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN);
+      cy.get(DEFINITION_DETAILS).within(() => {
+        getDetails(DATA_VIEW_DETAILS).should('have.text', this.rule.dataSource.dataView);
+        getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery);
+        getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query');
+        getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
+      });
+      cy.get(DEFINITION_DETAILS).should('not.contain', INDEX_PATTERNS_DETAILS);
+      cy.get(SCHEDULE_DETAILS).within(() => {
+        getDetails(RUNS_EVERY_DETAILS).should(
+          'have.text',
+          `${getDataViewRule().runsEvery.interval}${getDataViewRule().runsEvery.type}`
+        );
+        getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
+          'have.text',
+          `${getDataViewRule().lookBack.interval}${getDataViewRule().lookBack.type}`
+        );
+      });
+
+      waitForTheRuleToBeExecuted();
+      waitForAlertsToPopulate();
+
+      cy.get(NUMBER_OF_ALERTS)
+        .invoke('text')
+        .should('match', /^[1-9].+$/);
+      cy.get(ALERT_GRID_CELL).contains(this.rule.name);
+    });
+  });
+});
diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts
index faa907be8810c..7c3ba64536faf 100644
--- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts
@@ -205,12 +205,12 @@ describe('indicator match', () => {
 
       describe('Indicator mapping', () => {
         beforeEach(() => {
+          const rule = getNewThreatIndicatorRule();
           visitWithoutDateRange(RULE_CREATION);
           selectIndicatorMatchType();
-          fillIndexAndIndicatorIndexPattern(
-            getNewThreatIndicatorRule().index,
-            getNewThreatIndicatorRule().indicatorIndexPattern
-          );
+          if (rule.dataSource.type === 'indexPatterns') {
+            fillIndexAndIndicatorIndexPattern(rule.dataSource.index, rule.indicatorIndexPattern);
+          }
         });
 
         it('Does NOT show invalidation text on initial page load', () => {
@@ -419,11 +419,12 @@ describe('indicator match', () => {
       });
 
       it('Creates and enables a new Indicator Match rule', () => {
+        const rule = getNewThreatIndicatorRule();
         visitWithoutDateRange(RULE_CREATION);
         selectIndicatorMatchType();
-        fillDefineIndicatorMatchRuleAndContinue(getNewThreatIndicatorRule());
-        fillAboutRuleAndContinue(getNewThreatIndicatorRule());
-        fillScheduleRuleAndContinue(getNewThreatIndicatorRule());
+        fillDefineIndicatorMatchRuleAndContinue(rule);
+        fillAboutRuleAndContinue(rule);
+        fillScheduleRuleAndContinue(rule);
         createAndEnableRule();
 
         cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
@@ -432,22 +433,19 @@ describe('indicator match', () => {
           cy.wrap($table.find(RULES_ROW).length).should('eql', expectedNumberOfRules);
         });
 
-        cy.get(RULE_NAME).should('have.text', getNewThreatIndicatorRule().name);
-        cy.get(RISK_SCORE).should('have.text', getNewThreatIndicatorRule().riskScore);
-        cy.get(SEVERITY).should('have.text', getNewThreatIndicatorRule().severity);
+        cy.get(RULE_NAME).should('have.text', rule.name);
+        cy.get(RISK_SCORE).should('have.text', rule.riskScore);
+        cy.get(SEVERITY).should('have.text', rule.severity);
         cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');
 
         goToRuleDetails();
 
-        cy.get(RULE_NAME_HEADER).should('contain', `${getNewThreatIndicatorRule().name}`);
-        cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', getNewThreatIndicatorRule().description);
+        cy.get(RULE_NAME_HEADER).should('contain', `${rule.name}`);
+        cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', rule.description);
         cy.get(ABOUT_DETAILS).within(() => {
-          getDetails(SEVERITY_DETAILS).should('have.text', getNewThreatIndicatorRule().severity);
-          getDetails(RISK_SCORE_DETAILS).should('have.text', getNewThreatIndicatorRule().riskScore);
-          getDetails(INDICATOR_PREFIX_OVERRIDE).should(
-            'have.text',
-            getNewThreatIndicatorRule().threatIndicatorPath
-          );
+          getDetails(SEVERITY_DETAILS).should('have.text', rule.severity);
+          getDetails(RISK_SCORE_DETAILS).should('have.text', rule.riskScore);
+          getDetails(INDICATOR_PREFIX_OVERRIDE).should('have.text', rule.threatIndicatorPath);
           getDetails(REFERENCE_URLS_DETAILS).should((details) => {
             expect(removeExternalLinkText(details.text())).equal(expectedUrls);
           });
@@ -461,22 +459,19 @@ describe('indicator match', () => {
         cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN);
 
         cy.get(DEFINITION_DETAILS).within(() => {
-          getDetails(INDEX_PATTERNS_DETAILS).should(
-            'have.text',
-            getNewThreatIndicatorRule().index.join('')
-          );
+          if (rule.dataSource.type === 'indexPatterns') {
+            getDetails(INDEX_PATTERNS_DETAILS).should('have.text', rule.dataSource.index?.join(''));
+          }
           getDetails(CUSTOM_QUERY_DETAILS).should('have.text', '*:*');
           getDetails(RULE_TYPE_DETAILS).should('have.text', 'Indicator Match');
           getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
           getDetails(INDICATOR_INDEX_PATTERNS).should(
             'have.text',
-            getNewThreatIndicatorRule().indicatorIndexPattern.join('')
+            rule.indicatorIndexPattern.join('')
           );
           getDetails(INDICATOR_MAPPING).should(
             'have.text',
-            `${getNewThreatIndicatorRule().indicatorMappingField} MATCHES ${
-              getNewThreatIndicatorRule().indicatorIndexField
-            }`
+            `${rule.indicatorMappingField} MATCHES ${rule.indicatorIndexField}`
           );
           getDetails(INDICATOR_INDEX_QUERY).should('have.text', '*:*');
         });
@@ -484,15 +479,11 @@ describe('indicator match', () => {
         cy.get(SCHEDULE_DETAILS).within(() => {
           getDetails(RUNS_EVERY_DETAILS).should(
             'have.text',
-            `${getNewThreatIndicatorRule().runsEvery.interval}${
-              getNewThreatIndicatorRule().runsEvery.type
-            }`
+            `${rule.runsEvery.interval}${rule.runsEvery.type}`
           );
           getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
             'have.text',
-            `${getNewThreatIndicatorRule().lookBack.interval}${
-              getNewThreatIndicatorRule().lookBack.type
-            }`
+            `${rule.lookBack.interval}${rule.lookBack.type}`
           );
         });
 
@@ -500,11 +491,9 @@ describe('indicator match', () => {
         waitForAlertsToPopulate();
 
         cy.get(NUMBER_OF_ALERTS).should('have.text', expectedNumberOfAlerts);
-        cy.get(ALERT_RULE_NAME).first().should('have.text', getNewThreatIndicatorRule().name);
-        cy.get(ALERT_SEVERITY)
-          .first()
-          .should('have.text', getNewThreatIndicatorRule().severity.toLowerCase());
-        cy.get(ALERT_RISK_SCORE).first().should('have.text', getNewThreatIndicatorRule().riskScore);
+        cy.get(ALERT_RULE_NAME).first().should('have.text', rule.name);
+        cy.get(ALERT_SEVERITY).first().should('have.text', rule.severity.toLowerCase());
+        cy.get(ALERT_RISK_SCORE).first().should('have.text', rule.riskScore);
       });
 
       it('Investigate alert in timeline', () => {
diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts
index 9673de50bbae9..4e2b42c7b7ee1 100644
--- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts
@@ -6,8 +6,7 @@
  */
 
 import { formatMitreAttackDescription } from '../../helpers/rules';
-import type { ThresholdRule } from '../../objects/rule';
-import { getIndexPatterns, getNewRule, getNewThresholdRule } from '../../objects/rule';
+import { getIndexPatterns, getNewThresholdRule } from '../../objects/rule';
 
 import { ALERT_GRID_CELL, NUMBER_OF_ALERTS } from '../../screens/alerts';
 
@@ -20,7 +19,6 @@ import {
   RULES_TABLE,
   SEVERITY,
 } from '../../screens/alerts_detection_rules';
-import { PREVIEW_HEADER_SUBTITLE } from '../../screens/create_new_rule';
 import {
   ABOUT_DETAILS,
   ABOUT_INVESTIGATION_NOTES,
@@ -47,22 +45,14 @@ import {
 } from '../../screens/rule_details';
 
 import { getDetails } from '../../tasks/rule_details';
-import { goToManageAlertsDetectionRules } from '../../tasks/alerts';
-import {
-  goToCreateNewRule,
-  goToRuleDetails,
-  waitForRulesTableToBeLoaded,
-} from '../../tasks/alerts_detection_rules';
-import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
+import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
 import { createTimeline } from '../../tasks/api_calls/timelines';
 import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
 import {
   createAndEnableRule,
   fillAboutRuleAndContinue,
   fillDefineThresholdRuleAndContinue,
-  fillDefineThresholdRule,
   fillScheduleRuleAndContinue,
-  previewResults,
   selectThresholdRuleType,
   waitForAlertsToPopulate,
   waitForTheRuleToBeExecuted,
@@ -156,37 +146,4 @@ describe('Detection rules, threshold', () => {
     cy.get(NUMBER_OF_ALERTS).should(($count) => expect(+$count.text().split(' ')[0]).to.be.lt(100));
     cy.get(ALERT_GRID_CELL).contains(rule.name);
   });
-
-  it.skip('Preview results of keyword using "host.name"', () => {
-    rule.index = [...rule.index, '.siem-signals*'];
-
-    createCustomRuleEnabled(getNewRule());
-    goToManageAlertsDetectionRules();
-    waitForRulesTableToBeLoaded();
-    goToCreateNewRule();
-    selectThresholdRuleType();
-    fillDefineThresholdRule(rule);
-    previewResults();
-
-    cy.get(PREVIEW_HEADER_SUBTITLE).should('have.text', '3 unique hits');
-  });
-
-  it.skip('Preview results of "ip" using "source.ip"', () => {
-    const previewRule: ThresholdRule = {
-      ...rule,
-      thresholdField: 'source.ip',
-      threshold: '1',
-    };
-    previewRule.index = [...previewRule.index, '.siem-signals*'];
-
-    createCustomRuleEnabled(getNewRule());
-    goToManageAlertsDetectionRules();
-    waitForRulesTableToBeLoaded();
-    goToCreateNewRule();
-    selectThresholdRuleType();
-    fillDefineThresholdRule(previewRule);
-    previewResults();
-
-    cy.get(PREVIEW_HEADER_SUBTITLE).should('have.text', '10 unique hits');
-  });
 });
diff --git a/x-pack/plugins/security_solution/cypress/integration/exceptions/add_exception.spec.ts b/x-pack/plugins/security_solution/cypress/integration/exceptions/add_exception.spec.ts
index 814f29622f51a..ac2fdf96be022 100644
--- a/x-pack/plugins/security_solution/cypress/integration/exceptions/add_exception.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/exceptions/add_exception.spec.ts
@@ -40,7 +40,11 @@ describe('Adds rule exception', () => {
   beforeEach(() => {
     deleteAlertsAndRules();
     createCustomRuleEnabled(
-      { ...getNewRule(), customQuery: 'agent.name:*', index: ['exceptions*'] },
+      {
+        ...getNewRule(),
+        customQuery: 'agent.name:*',
+        dataSource: { index: ['exceptions*'], type: 'indexPatterns' },
+      },
       'rule_testing',
       '1s'
     );
diff --git a/x-pack/plugins/security_solution/cypress/integration/exceptions/exceptions_flyout.spec.ts b/x-pack/plugins/security_solution/cypress/integration/exceptions/exceptions_flyout.spec.ts
index 9e08313e7e73f..8c2e2af4b8bad 100644
--- a/x-pack/plugins/security_solution/cypress/integration/exceptions/exceptions_flyout.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/exceptions/exceptions_flyout.spec.ts
@@ -70,7 +70,7 @@ describe('Exceptions flyout', () => {
     createExceptionList(getExceptionList(), getExceptionList().list_id).then((response) =>
       createCustomRule({
         ...getNewRule(),
-        index: ['exceptions-*'],
+        dataSource: { index: ['exceptions-*'], type: 'indexPatterns' },
         exceptionLists: [
           {
             id: response.body.id,
diff --git a/x-pack/plugins/security_solution/cypress/objects/rule.ts b/x-pack/plugins/security_solution/cypress/objects/rule.ts
index 17ffdf52486f5..7fd9e7b5f7625 100644
--- a/x-pack/plugins/security_solution/cypress/objects/rule.ts
+++ b/x-pack/plugins/security_solution/cypress/objects/rule.ts
@@ -37,11 +37,15 @@ interface Interval {
   type: string;
 }
 
+export type RuleDataSource =
+  | { type: 'indexPatterns'; index: string[] }
+  | { type: 'dataView'; dataView: string };
+
 export interface CustomRule {
   customQuery?: string;
   name: string;
   description: string;
-  index: string[];
+  dataSource: RuleDataSource;
   interval?: string;
   severity: string;
   riskScore: string;
@@ -176,15 +180,39 @@ const getRunsEvery = (): Interval => ({
   type: 's',
 });
 
+const getRunsEveryFiveMinutes = (): Interval => ({
+  interval: '5',
+  timeType: 'Minutes',
+  type: 'm',
+});
+
 const getLookBack = (): Interval => ({
   interval: '50000',
   timeType: 'Hours',
   type: 'h',
 });
 
+export const getDataViewRule = (): CustomRule => ({
+  customQuery: 'host.name: *',
+  dataSource: { dataView: 'auditbeat-2022', type: 'dataView' },
+  name: 'New Data View Rule',
+  description: 'The new rule description.',
+  severity: 'High',
+  riskScore: '17',
+  tags: ['test', 'newRule'],
+  referenceUrls: ['http://example.com/', 'https://example.com/'],
+  falsePositivesExamples: ['False1', 'False2'],
+  mitre: [getMitre1(), getMitre2()],
+  note: '# test markdown',
+  runsEvery: getRunsEveryFiveMinutes(),
+  lookBack: getLookBack(),
+  timeline: getTimeline(),
+  maxSignals: 100,
+});
+
 export const getNewRule = (): CustomRule => ({
   customQuery: 'host.name: *',
-  index: getIndexPatterns(),
+  dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
   name: 'New Rule Test',
   description: 'The new rule description.',
   severity: 'High',
@@ -202,7 +230,7 @@ export const getNewRule = (): CustomRule => ({
 
 export const getBuildingBlockRule = (): CustomRule => ({
   customQuery: 'host.name: *',
-  index: getIndexPatterns(),
+  dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
   name: 'Building Block Rule Test',
   description: 'The new rule description.',
   severity: 'High',
@@ -221,7 +249,7 @@ export const getBuildingBlockRule = (): CustomRule => ({
 
 export const getUnmappedRule = (): CustomRule => ({
   customQuery: '*:*',
-  index: ['unmapped*'],
+  dataSource: { index: ['unmapped*'], type: 'indexPatterns' },
   name: 'Rule with unmapped fields',
   description: 'The new rule description.',
   severity: 'High',
@@ -239,7 +267,7 @@ export const getUnmappedRule = (): CustomRule => ({
 
 export const getUnmappedCCSRule = (): CustomRule => ({
   customQuery: '*:*',
-  index: [`${ccsRemoteName}:unmapped*`],
+  dataSource: { index: [`${ccsRemoteName}:unmapped*`], type: 'indexPatterns' },
   name: 'Rule with unmapped fields',
   description: 'The new rule description.',
   severity: 'High',
@@ -259,7 +287,7 @@ export const getExistingRule = (): CustomRule => ({
   customQuery: 'host.name: *',
   name: 'Rule 1',
   description: 'Description for Rule 1',
-  index: ['auditbeat-*'],
+  dataSource: { index: ['auditbeat-*'], type: 'indexPatterns' },
   interval: '100m',
   severity: 'High',
   riskScore: '19',
@@ -278,7 +306,7 @@ export const getExistingRule = (): CustomRule => ({
 
 export const getNewOverrideRule = (): OverrideRule => ({
   customQuery: 'host.name: *',
-  index: getIndexPatterns(),
+  dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
   name: 'Override Rule',
   description: 'The new rule description.',
   severity: 'High',
@@ -305,7 +333,7 @@ export const getNewOverrideRule = (): OverrideRule => ({
 
 export const getNewThresholdRule = (): ThresholdRule => ({
   customQuery: 'host.name: *',
-  index: getIndexPatterns(),
+  dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
   name: 'Threshold Rule',
   description: 'The new rule description.',
   severity: 'High',
@@ -325,7 +353,7 @@ export const getNewThresholdRule = (): ThresholdRule => ({
 
 export const getNewTermsRule = (): NewTermsRule => ({
   customQuery: 'host.name: *',
-  index: getIndexPatterns(),
+  dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
   name: 'New Terms Rule',
   description: 'The new rule description.',
   severity: 'High',
@@ -365,7 +393,7 @@ export const getMachineLearningRule = (): MachineLearningRule => ({
 export const getEqlRule = (): CustomRule => ({
   customQuery: 'any where process.name == "zsh"',
   name: 'New EQL Rule',
-  index: getIndexPatterns(),
+  dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
   description: 'New EQL rule description.',
   severity: 'High',
   riskScore: '17',
@@ -383,7 +411,7 @@ export const getEqlRule = (): CustomRule => ({
 export const getCCSEqlRule = (): CustomRule => ({
   customQuery: 'any where process.name == "run-parts"',
   name: 'New EQL Rule',
-  index: [`${ccsRemoteName}:run-parts`],
+  dataSource: { index: [`${ccsRemoteName}:run-parts`], type: 'indexPatterns' },
   description: 'New EQL rule description.',
   severity: 'High',
   riskScore: '17',
@@ -404,7 +432,7 @@ export const getEqlSequenceRule = (): CustomRule => ({
      [any where agent.name == "test.local"]\
      [any where host.name == "test.local"]',
   name: 'New EQL Sequence Rule',
-  index: getIndexPatterns(),
+  dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
   description: 'New EQL rule description.',
   severity: 'High',
   riskScore: '17',
@@ -422,7 +450,7 @@ export const getEqlSequenceRule = (): CustomRule => ({
 export const getNewThreatIndicatorRule = (): ThreatIndicatorRule => ({
   name: 'Threat Indicator Rule Test',
   description: 'The threat indicator rule description.',
-  index: ['suspicious-*'],
+  dataSource: { index: ['suspicious-*'], type: 'indexPatterns' },
   severity: 'Critical',
   riskScore: '20',
   tags: ['test', 'threat'],
diff --git a/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts
index 7af92d518db7a..00fb1ad0abe55 100644
--- a/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts
+++ b/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts
@@ -93,6 +93,11 @@ export const AT_LEAST_ONE_INDEX_PATTERN = 'A minimum of one index pattern is req
 
 export const CUSTOM_QUERY_REQUIRED = 'A custom query is required.';
 
+export const DATA_VIEW_COMBO_BOX =
+  '[data-test-subj="pick-rule-data-source"] [data-test-subj="comboBoxInput"]';
+
+export const DATA_VIEW_OPTION = '[data-test-subj="rule-index-toggle-dataView"]';
+
 export const DEFINE_CONTINUE_BUTTON = '[data-test-subj="define-continue"]';
 
 export const DEFINE_EDIT_BUTTON = '[data-test-subj="edit-define-rule"]';
diff --git a/x-pack/plugins/security_solution/cypress/screens/rule_details.ts b/x-pack/plugins/security_solution/cypress/screens/rule_details.ts
index a541cf5cb2bc6..4aed5286ee1f1 100644
--- a/x-pack/plugins/security_solution/cypress/screens/rule_details.ts
+++ b/x-pack/plugins/security_solution/cypress/screens/rule_details.ts
@@ -22,6 +22,8 @@ export const ANOMALY_SCORE_DETAILS = 'Anomaly score';
 
 export const CUSTOM_QUERY_DETAILS = 'Custom query';
 
+export const DATA_VIEW_DETAILS = 'Data View';
+
 export const DEFINITION_DETAILS =
   '[data-test-subj=definitionRule] [data-test-subj="listItemColumnStepRuleDescription"]';
 
diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts
index 88616063c6c36..0ef07195b3309 100644
--- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts
+++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts
@@ -28,7 +28,11 @@ export const createMachineLearningRule = (rule: MachineLearningRule, ruleId = 'm
     failOnStatusCode: false,
   });
 
-export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing', interval = '100m') =>
+export const createCustomRule = (
+  rule: CustomRule,
+  ruleId = 'rule_testing',
+  interval = '100m'
+): Cypress.Chainable<Cypress.Response<unknown>> =>
   cy.request({
     method: 'POST',
     url: 'api/detection_engine/rules',
@@ -41,7 +45,7 @@ export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing', inte
       severity: rule.severity.toLocaleLowerCase(),
       type: 'query',
       from: 'now-50000h',
-      index: rule.index,
+      index: rule.dataSource.type === 'indexPatterns' ? rule.dataSource.index : '',
       query: rule.customQuery,
       language: 'kuery',
       enabled: false,
@@ -51,98 +55,107 @@ export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing', inte
     failOnStatusCode: false,
   });
 
-export const createEventCorrelationRule = (rule: CustomRule, ruleId = 'rule_testing') =>
-  cy.request({
-    method: 'POST',
-    url: 'api/detection_engine/rules',
-    body: {
-      rule_id: ruleId,
-      risk_score: parseInt(rule.riskScore, 10),
-      description: rule.description,
-      interval: `${rule.runsEvery.interval}${rule.runsEvery.type}`,
-      from: `now-${rule.lookBack.interval}${rule.lookBack.type}`,
-      name: rule.name,
-      severity: rule.severity.toLocaleLowerCase(),
-      type: 'eql',
-      index: rule.index,
-      query: rule.customQuery,
-      language: 'eql',
-      enabled: true,
-    },
-    headers: { 'kbn-xsrf': 'cypress-creds' },
-  });
+export const createEventCorrelationRule = (rule: CustomRule, ruleId = 'rule_testing') => {
+  if (rule.dataSource.type === 'indexPatterns') {
+    cy.request({
+      method: 'POST',
+      url: 'api/detection_engine/rules',
+      body: {
+        rule_id: ruleId,
+        risk_score: parseInt(rule.riskScore, 10),
+        description: rule.description,
+        interval: `${rule.runsEvery.interval}${rule.runsEvery.type}`,
+        from: `now-${rule.lookBack.interval}${rule.lookBack.type}`,
+        name: rule.name,
+        severity: rule.severity.toLocaleLowerCase(),
+        type: 'eql',
+        index: rule.dataSource.index,
+        query: rule.customQuery,
+        language: 'eql',
+        enabled: true,
+      },
+      headers: { 'kbn-xsrf': 'cypress-creds' },
+    });
+  }
+};
 
-export const createCustomIndicatorRule = (rule: ThreatIndicatorRule, ruleId = 'rule_testing') =>
-  cy.request({
-    method: 'POST',
-    url: 'api/detection_engine/rules',
-    body: {
-      rule_id: ruleId,
-      risk_score: parseInt(rule.riskScore, 10),
-      description: rule.description,
-      // Default interval is 1m, our tests config overwrite this to 1s
-      // See https://github.com/elastic/kibana/pull/125396 for details
-      interval: '10s',
-      name: rule.name,
-      severity: rule.severity.toLocaleLowerCase(),
-      type: 'threat_match',
-      timeline_id: rule.timeline.templateTimelineId,
-      timeline_title: rule.timeline.title,
-      threat_mapping: [
-        {
-          entries: [
-            {
-              field: rule.indicatorMappingField,
-              type: 'mapping',
-              value: rule.indicatorIndexField,
-            },
-          ],
-        },
-      ],
-      threat_query: '*:*',
-      threat_language: 'kuery',
-      threat_filters: [],
-      threat_index: rule.indicatorIndexPattern,
-      threat_indicator_path: rule.threatIndicatorPath,
-      from: 'now-50000h',
-      index: rule.index,
-      query: rule.customQuery || '*:*',
-      language: 'kuery',
-      enabled: true,
-    },
-    headers: { 'kbn-xsrf': 'cypress-creds' },
-    failOnStatusCode: false,
-  });
+export const createCustomIndicatorRule = (rule: ThreatIndicatorRule, ruleId = 'rule_testing') => {
+  if (rule.dataSource.type === 'indexPatterns') {
+    cy.request({
+      method: 'POST',
+      url: 'api/detection_engine/rules',
+      body: {
+        rule_id: ruleId,
+        risk_score: parseInt(rule.riskScore, 10),
+        description: rule.description,
+        // Default interval is 1m, our tests config overwrite this to 1s
+        // See https://github.com/elastic/kibana/pull/125396 for details
+        interval: '10s',
+        name: rule.name,
+        severity: rule.severity.toLocaleLowerCase(),
+        type: 'threat_match',
+        timeline_id: rule.timeline.templateTimelineId,
+        timeline_title: rule.timeline.title,
+        threat_mapping: [
+          {
+            entries: [
+              {
+                field: rule.indicatorMappingField,
+                type: 'mapping',
+                value: rule.indicatorIndexField,
+              },
+            ],
+          },
+        ],
+        threat_query: '*:*',
+        threat_language: 'kuery',
+        threat_filters: [],
+        threat_index: rule.indicatorIndexPattern,
+        threat_indicator_path: rule.threatIndicatorPath,
+        from: 'now-50000h',
+        index: rule.dataSource.index,
+        query: rule.customQuery || '*:*',
+        language: 'kuery',
+        enabled: true,
+      },
+      headers: { 'kbn-xsrf': 'cypress-creds' },
+      failOnStatusCode: false,
+    });
+  }
+};
 
 export const createCustomRuleEnabled = (
   rule: CustomRule,
   ruleId = '1',
   interval = '100m',
   maxSignals = 500
-) =>
-  cy.request({
-    method: 'POST',
-    url: 'api/detection_engine/rules',
-    body: {
-      rule_id: ruleId,
-      risk_score: parseInt(rule.riskScore, 10),
-      description: rule.description,
-      interval,
-      name: rule.name,
-      severity: rule.severity.toLocaleLowerCase(),
-      type: 'query',
-      from: 'now-50000h',
-      index: rule.index,
-      query: rule.customQuery,
-      language: 'kuery',
-      enabled: true,
-      tags: ['rule1'],
-      max_signals: maxSignals,
-      building_block_type: rule.buildingBlockType,
-    },
-    headers: { 'kbn-xsrf': 'cypress-creds' },
-    failOnStatusCode: false,
-  });
+) => {
+  if (rule.dataSource.type === 'indexPatterns') {
+    cy.request({
+      method: 'POST',
+      url: 'api/detection_engine/rules',
+      body: {
+        rule_id: ruleId,
+        risk_score: parseInt(rule.riskScore, 10),
+        description: rule.description,
+        interval,
+        name: rule.name,
+        severity: rule.severity.toLocaleLowerCase(),
+        type: 'query',
+        from: 'now-50000h',
+        index: rule.dataSource.index,
+        query: rule.customQuery,
+        language: 'kuery',
+        enabled: true,
+        tags: ['rule1'],
+        max_signals: maxSignals,
+        building_block_type: rule.buildingBlockType,
+      },
+      headers: { 'kbn-xsrf': 'cypress-creds' },
+      failOnStatusCode: false,
+    });
+  }
+};
 
 export const deleteCustomRule = (ruleId = '1') => {
   cy.request({
diff --git a/x-pack/plugins/security_solution/cypress/tasks/common.ts b/x-pack/plugins/security_solution/cypress/tasks/common.ts
index 437ed1a254ca4..4982053648667 100644
--- a/x-pack/plugins/security_solution/cypress/tasks/common.ts
+++ b/x-pack/plugins/security_solution/cypress/tasks/common.ts
@@ -179,14 +179,14 @@ export const deleteCases = () => {
   });
 };
 
-export const postDataView = (indexPattern: string) => {
+export const postDataView = (dataSource: string) => {
   cy.request({
     method: 'POST',
     url: `/api/index_patterns/index_pattern`,
     body: {
       index_pattern: {
         fieldAttrs: '{}',
-        title: indexPattern,
+        title: dataSource,
         timeFieldName: '@timestamp',
         fields: '{}',
       },
diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
index 5e5de7301362b..8d1c1ebc94eb5 100644
--- a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
+++ b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
@@ -94,6 +94,8 @@ import {
   EMAIL_CONNECTOR_PASSWORD_INPUT,
   EMAIL_CONNECTOR_SERVICE_SELECTOR,
   PREVIEW_HISTOGRAM,
+  DATA_VIEW_COMBO_BOX,
+  DATA_VIEW_OPTION,
   NEW_TERMS_TYPE,
   NEW_TERMS_HISTORY_SIZE,
   NEW_TERMS_HISTORY_TIME_TYPE,
@@ -258,6 +260,10 @@ export const fillAboutRuleWithOverrideAndContinue = (rule: OverrideRule) => {
 export const fillDefineCustomRuleWithImportedQueryAndContinue = (
   rule: CustomRule | OverrideRule
 ) => {
+  if (rule.dataSource.type === 'dataView') {
+    cy.get(DATA_VIEW_OPTION).click();
+    cy.get(DATA_VIEW_COMBO_BOX).type(`${rule.dataSource.dataView}{enter}`);
+  }
   cy.get(IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK).click();
   cy.get(TIMELINE(rule.timeline.id)).click();
   cy.get(CUSTOM_QUERY_INPUT).should('have.value', rule.customQuery);
@@ -282,9 +288,11 @@ export const fillDefineThresholdRule = (rule: ThresholdRule) => {
   cy.get(TIMELINE(rule.timeline.id)).click();
   cy.get(COMBO_BOX_CLEAR_BTN).first().click();
 
-  rule.index.forEach((index) => {
-    cy.get(COMBO_BOX_INPUT).first().type(`${index}{enter}`);
-  });
+  if (rule.dataSource.type === 'indexPatterns') {
+    rule.dataSource.index.forEach((index) => {
+      cy.get(COMBO_BOX_INPUT).first().type(`${index}{enter}`);
+    });
+  }
 
   cy.get(CUSTOM_QUERY_INPUT).should('have.value', rule.customQuery);
   cy.get(THRESHOLD_INPUT_AREA)
@@ -494,7 +502,9 @@ export const getCustomQueryInvalidationText = () => cy.contains(CUSTOM_QUERY_REQ
  * @param rule The rule to use to fill in everything
  */
 export const fillDefineIndicatorMatchRuleAndContinue = (rule: ThreatIndicatorRule) => {
-  fillIndexAndIndicatorIndexPattern(rule.index, rule.indicatorIndexPattern);
+  if (rule.dataSource.type === 'indexPatterns') {
+    fillIndexAndIndicatorIndexPattern(rule.dataSource.index, rule.indicatorIndexPattern);
+  }
   fillIndicatorMatchRow({
     indexField: rule.indicatorMappingField,
     indicatorIndexField: rule.indicatorIndexField,