diff --git a/frontend/src/metabase-lib/lib/Question.js b/frontend/src/metabase-lib/lib/Question.js
index 4759faed28a67577629646a89788deb5872d0291..14bf1ae6848574352f228445e5fab9fbaae80295 100644
--- a/frontend/src/metabase-lib/lib/Question.js
+++ b/frontend/src/metabase-lib/lib/Question.js
@@ -34,10 +34,8 @@ import {
   findColumnSettingIndexForColumn,
   syncTableColumnsToQuery,
 } from "metabase/lib/dataset";
-import {
-  getValueAndFieldIdPopulatedParametersFromCard,
-  isTransientId,
-} from "metabase/meta/Card";
+import { isTransientId } from "metabase/meta/Card";
+import { getValueAndFieldIdPopulatedParametersFromCard } from "metabase/parameters/utils/cards";
 import { parameterToMBQLFilter } from "metabase/parameters/utils/mbql";
 import { normalizeParameterValue } from "metabase/parameters/utils/parameter-values";
 import {
diff --git a/frontend/src/metabase/dashboard/components/ParametersPopover.jsx b/frontend/src/metabase/dashboard/components/ParametersPopover.jsx
index d4a0fbe6bcc827fcdd53065a194a45b5e0bae295..50da002e0bb752a8210d90ef6db3b0651265fc8f 100644
--- a/frontend/src/metabase/dashboard/components/ParametersPopover.jsx
+++ b/frontend/src/metabase/dashboard/components/ParametersPopover.jsx
@@ -2,7 +2,7 @@ import React, { Component } from "react";
 import { t } from "ttag";
 import { getDashboardParameterSections } from "metabase/parameters/utils/dashboard-options";
 import Icon from "metabase/components/Icon";
-import { getParameterIconName } from "metabase/meta/Parameter";
+import { getParameterIconName } from "metabase/parameters/utils/ui";
 import styled from "styled-components";
 
 import type {
diff --git a/frontend/src/metabase/meta/Card.js b/frontend/src/metabase/meta/Card.js
index 49e4a0a41c00da6207ddbedb3e1b2bc4cbd059b0..2900230f1486311de3a28f32176cc33ad54f52b9 100644
--- a/frontend/src/metabase/meta/Card.js
+++ b/frontend/src/metabase/meta/Card.js
@@ -1,21 +1,16 @@
-import { getTemplateTagParameters } from "metabase/meta/Parameter";
+import _ from "underscore";
+import { assoc, updateIn } from "icepick";
+
+import { getParametersFromCard } from "metabase/parameters/utils/cards";
 import { parameterToMBQLFilter } from "metabase/parameters/utils/mbql";
-import { getParameterTargetField } from "metabase/parameters/utils/targets";
-import {
-  normalizeParameterValue,
-  getValuePopulatedParameters,
-} from "metabase/parameters/utils/parameter-values";
+import { normalizeParameterValue } from "metabase/parameters/utils/parameter-values";
 
 import * as Query from "metabase/lib/query/query";
 import * as Q_DEPRECATED from "metabase/lib/query"; // legacy
 import Utils from "metabase/lib/utils";
 import * as Urls from "metabase/lib/urls";
-import Question from "metabase-lib/lib/Question";
-
-import _ from "underscore";
-import { assoc, updateIn } from "icepick";
 
-import type { StructuredQuery, TemplateTag } from "metabase-types/types/Query";
+import type { StructuredQuery } from "metabase-types/types/Query";
 import type {
   Card,
   DatasetQuery,
@@ -30,10 +25,6 @@ import type {
 import type Metadata from "metabase-lib/lib/metadata/Metadata";
 import type Table from "metabase-lib/lib/metadata/Table";
 
-declare class Object {
-  static values<T>(object: { [key: string]: T }): Array<T>;
-}
-
 // TODO Atte Keinänen 6/5/17 Should these be moved to corresponding metabase-lib classes?
 // Is there any reason behind keeping them in a central place?
 
@@ -113,53 +104,6 @@ export function getTableMetadata(card: Card, metadata: Metadata): ?Table {
   return null;
 }
 
-export function getTemplateTagsForParameters(card: ?Card): Array<TemplateTag> {
-  const templateTags =
-    card &&
-    card.dataset_query &&
-    card.dataset_query.type === "native" &&
-    card.dataset_query.native["template-tags"]
-      ? Object.values(card.dataset_query.native["template-tags"])
-      : [];
-  return templateTags.filter(
-    // this should only return template tags that define a parameter of the card
-    tag => tag.type !== "card" && tag.type !== "snippet",
-  );
-}
-
-export function getParametersFromCard(card: ?Card): Parameter[] {
-  if (card && card.parameters) {
-    return card.parameters;
-  }
-
-  const tags: TemplateTag[] = getTemplateTagsForParameters(card);
-  return getTemplateTagParameters(tags);
-}
-
-export function getValueAndFieldIdPopulatedParametersFromCard(
-  card: Card,
-  metadata,
-  parameterValues?: ParameterValues,
-): Parameter[] {
-  const parameters = getParametersFromCard(card);
-  const valuePopulatedParameters = getValuePopulatedParameters(
-    parameters,
-    parameterValues,
-  );
-  const question = new Question(card, metadata);
-
-  return valuePopulatedParameters.map(parameter => {
-    // if we have a field id for this parameter, set "field_id"
-    const field = getParameterTargetField(parameter.target, metadata, question);
-    if (field != null) {
-      parameter = assoc(parameter, "fields", [field]);
-      parameter = assoc(parameter, "field_id", field.id);
-    }
-    parameter = assoc(parameter, "hasOnlyFieldTargets", field != null);
-    return parameter;
-  });
-}
-
 // NOTE Atte Keinänen 7/5/17: Still used in dashboards and public questions.
 // Query builder uses `Question.getResults` which contains similar logic.
 export function applyParameters(
diff --git a/frontend/src/metabase/meta/Parameter.js b/frontend/src/metabase/meta/Parameter.js
deleted file mode 100644
index a862dae0c9a990cc08af31da5345f2b8a0c43001..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/meta/Parameter.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import MetabaseSettings from "metabase/lib/settings";
-import type { TemplateTag } from "metabase-types/types/Query";
-import type { Parameter } from "metabase-types/types/Parameter";
-import _ from "underscore";
-import { getParameterType } from "metabase/parameters/utils/parameter-type";
-
-const areFieldFilterOperatorsEnabled = () =>
-  MetabaseSettings.get("field-filter-operators-enabled?");
-
-// NOTE: this should mirror `template-tag-parameters` in src/metabase/api/embed.clj
-export function getTemplateTagParameters(tags: TemplateTag[]): Parameter[] {
-  function getTemplateTagType(tag) {
-    const { type } = tag;
-    if (type === "date") {
-      return "date/single";
-    } else if (areFieldFilterOperatorsEnabled() && type === "string") {
-      return "string/=";
-    } else if (areFieldFilterOperatorsEnabled() && type === "number") {
-      return "number/=";
-    } else {
-      return "category";
-    }
-  }
-
-  return tags
-    .filter(
-      tag =>
-        tag.type != null && (tag["widget-type"] || tag.type !== "dimension"),
-    )
-    .map(tag => {
-      return {
-        id: tag.id,
-        type: tag["widget-type"] || getTemplateTagType(tag),
-        target:
-          tag.type === "dimension"
-            ? ["dimension", ["template-tag", tag.name]]
-            : ["variable", ["template-tag", tag.name]],
-        name: tag["display-name"],
-        slug: tag.name,
-        default: tag.default,
-      };
-    });
-}
-
-export function getParameterIconName(parameter: ?Parameter) {
-  const type = getParameterType(parameter);
-  switch (type) {
-    case "date":
-      return "calendar";
-    case "location":
-      return "location";
-    case "category":
-      return "string";
-    case "number":
-      return "number";
-    case "id":
-    default:
-      return "label";
-  }
-}
-
-export function buildHiddenParametersSlugSet(hiddenParameterSlugs) {
-  return _.isString(hiddenParameterSlugs)
-    ? new Set(hiddenParameterSlugs.split(","))
-    : new Set();
-}
-
-export function getVisibleParameters(parameters, hiddenParameterSlugs) {
-  const hiddenParametersSlugSet = buildHiddenParametersSlugSet(
-    hiddenParameterSlugs,
-  );
-
-  return parameters.filter(p => !hiddenParametersSlugSet.has(p.slug));
-}
diff --git a/frontend/src/metabase/parameters/components/ParameterValueWidget.jsx b/frontend/src/metabase/parameters/components/ParameterValueWidget.jsx
index a20d22107773e05a4a9f71b21218097916209865..27420d5fac0985217ff838a7afd95f369e328ca9 100644
--- a/frontend/src/metabase/parameters/components/ParameterValueWidget.jsx
+++ b/frontend/src/metabase/parameters/components/ParameterValueWidget.jsx
@@ -23,7 +23,7 @@ import {
   makeGetMergedParameterFieldValues,
 } from "metabase/selectors/metadata";
 
-import { getParameterIconName } from "metabase/meta/Parameter";
+import { getParameterIconName } from "metabase/parameters/utils/ui";
 import { deriveFieldOperatorFromParameter } from "metabase/parameters/utils/operators";
 import { isDashboardParameterWithoutMapping } from "metabase/meta/Dashboard";
 
diff --git a/frontend/src/metabase/parameters/components/ParametersList.jsx b/frontend/src/metabase/parameters/components/ParametersList.jsx
index a4879c224a00ea2bd699195229ae76d81ff58bbb..01e81b76547b47017337d4662fbfcd96783d22ab 100644
--- a/frontend/src/metabase/parameters/components/ParametersList.jsx
+++ b/frontend/src/metabase/parameters/components/ParametersList.jsx
@@ -9,7 +9,7 @@ import {
   SortableElement,
   SortableHandle,
 } from "metabase/components/sortable";
-import { getVisibleParameters } from "metabase/meta/Parameter";
+import { getVisibleParameters } from "metabase/parameters/utils/ui";
 import { getValuePopulatedParameters } from "metabase/parameters/utils/parameter-values";
 
 import type {
diff --git a/frontend/src/metabase/parameters/utils/cards.js b/frontend/src/metabase/parameters/utils/cards.js
new file mode 100644
index 0000000000000000000000000000000000000000..9bfbbd104deb2aeeb35471969ad274d0f3e661ba
--- /dev/null
+++ b/frontend/src/metabase/parameters/utils/cards.js
@@ -0,0 +1,89 @@
+import { assoc } from "icepick";
+
+import Question from "metabase-lib/lib/Question";
+
+import { areFieldFilterOperatorsEnabled } from "./feature-flag";
+import { getParameterTargetField } from "metabase/parameters/utils/targets";
+import { getValuePopulatedParameters } from "metabase/parameters/utils/parameter-values";
+
+// NOTE: this should mirror `template-tag-parameters` in src/metabase/api/embed.clj
+export function getTemplateTagParameters(tags) {
+  function getTemplateTagType(tag) {
+    const { type } = tag;
+    if (type === "date") {
+      return "date/single";
+    } else if (areFieldFilterOperatorsEnabled() && type === "string") {
+      return "string/=";
+    } else if (areFieldFilterOperatorsEnabled() && type === "number") {
+      return "number/=";
+    } else {
+      return "category";
+    }
+  }
+
+  return tags
+    .filter(
+      tag =>
+        tag.type != null && (tag["widget-type"] || tag.type !== "dimension"),
+    )
+    .map(tag => {
+      return {
+        id: tag.id,
+        type: tag["widget-type"] || getTemplateTagType(tag),
+        target:
+          tag.type === "dimension"
+            ? ["dimension", ["template-tag", tag.name]]
+            : ["variable", ["template-tag", tag.name]],
+        name: tag["display-name"],
+        slug: tag.name,
+        default: tag.default,
+      };
+    });
+}
+
+export function getTemplateTagsForParameters(card) {
+  const templateTags =
+    card &&
+    card.dataset_query &&
+    card.dataset_query.type === "native" &&
+    card.dataset_query.native["template-tags"]
+      ? Object.values(card.dataset_query.native["template-tags"])
+      : [];
+  return templateTags.filter(
+    // this should only return template tags that define a parameter of the card
+    tag => tag.type !== "card" && tag.type !== "snippet",
+  );
+}
+
+export function getParametersFromCard(card) {
+  if (card && card.parameters) {
+    return card.parameters;
+  }
+
+  const tags = getTemplateTagsForParameters(card);
+  return getTemplateTagParameters(tags);
+}
+
+export function getValueAndFieldIdPopulatedParametersFromCard(
+  card,
+  metadata,
+  parameterValues,
+) {
+  const parameters = getParametersFromCard(card);
+  const valuePopulatedParameters = getValuePopulatedParameters(
+    parameters,
+    parameterValues,
+  );
+  const question = new Question(card, metadata);
+
+  return valuePopulatedParameters.map(parameter => {
+    // if we have a field id for this parameter, set "field_id"
+    const field = getParameterTargetField(parameter.target, metadata, question);
+    if (field != null) {
+      parameter = assoc(parameter, "fields", [field]);
+      parameter = assoc(parameter, "field_id", field.id);
+    }
+    parameter = assoc(parameter, "hasOnlyFieldTargets", field != null);
+    return parameter;
+  });
+}
diff --git a/frontend/test/metabase/meta/Parameter.unit.spec.js b/frontend/src/metabase/parameters/utils/cards.unit.spec.js
similarity index 75%
rename from frontend/test/metabase/meta/Parameter.unit.spec.js
rename to frontend/src/metabase/parameters/utils/cards.unit.spec.js
index b2946e76a70e2c35f8ed11f05773f99ed68c2ba8..3da8383cbc8c5ed6a7fa25b0829fe54c3e1182db 100644
--- a/frontend/test/metabase/meta/Parameter.unit.spec.js
+++ b/frontend/src/metabase/parameters/utils/cards.unit.spec.js
@@ -1,9 +1,5 @@
 import MetabaseSettings from "metabase/lib/settings";
-import {
-  getTemplateTagParameters,
-  buildHiddenParametersSlugSet,
-  getVisibleParameters,
-} from "metabase/meta/Parameter";
+import { getTemplateTagParameters } from "./cards";
 
 MetabaseSettings.get = jest.fn();
 
@@ -15,7 +11,7 @@ function mockFieldFilterOperatorsFlag(value) {
   });
 }
 
-describe("metabase/meta/Parameter", () => {
+describe("parameters/utils/cards", () => {
   beforeEach(() => {
     jest.clearAllMocks();
     MetabaseSettings.get.mockReturnValue(false);
@@ -174,53 +170,4 @@ describe("metabase/meta/Parameter", () => {
       });
     });
   });
-
-  describe("buildHiddenParametersSlugSet", () => {
-    it("should turn the given string of slugs separated by commas into a set of slug strings", () => {
-      expect(buildHiddenParametersSlugSet("a,b,c")).toEqual(
-        new Set(["a", "b", "c"]),
-      );
-    });
-
-    it("should return an empty set for any input that is not a string", () => {
-      expect(buildHiddenParametersSlugSet(undefined)).toEqual(new Set());
-      expect(buildHiddenParametersSlugSet(111111)).toEqual(new Set());
-    });
-  });
-
-  describe("getVisibleParameters", () => {
-    const parameters = [
-      {
-        id: 1,
-        slug: "foo",
-      },
-      {
-        id: 2,
-        slug: "bar",
-      },
-      {
-        id: 3,
-        slug: "baz",
-      },
-      {
-        id: 4,
-        slug: "qux",
-      },
-    ];
-
-    const hiddenParameterSlugs = "bar,baz";
-
-    it("should return the parameters that are not hidden", () => {
-      expect(getVisibleParameters(parameters, hiddenParameterSlugs)).toEqual([
-        {
-          id: 1,
-          slug: "foo",
-        },
-        {
-          id: 4,
-          slug: "qux",
-        },
-      ]);
-    });
-  });
 });
diff --git a/frontend/src/metabase/parameters/utils/ui.js b/frontend/src/metabase/parameters/utils/ui.js
new file mode 100644
index 0000000000000000000000000000000000000000..2abcf78ece709b9a335da5ee390e21e6df1c1d4f
--- /dev/null
+++ b/frontend/src/metabase/parameters/utils/ui.js
@@ -0,0 +1,33 @@
+import _ from "underscore";
+import { getParameterType } from "./parameter-type";
+
+export function getParameterIconName(parameter) {
+  const type = getParameterType(parameter);
+  switch (type) {
+    case "date":
+      return "calendar";
+    case "location":
+      return "location";
+    case "category":
+      return "string";
+    case "number":
+      return "number";
+    case "id":
+    default:
+      return "label";
+  }
+}
+
+export function buildHiddenParametersSlugSet(hiddenParameterSlugs) {
+  return _.isString(hiddenParameterSlugs)
+    ? new Set(hiddenParameterSlugs.split(","))
+    : new Set();
+}
+
+export function getVisibleParameters(parameters, hiddenParameterSlugs) {
+  const hiddenParametersSlugSet = buildHiddenParametersSlugSet(
+    hiddenParameterSlugs,
+  );
+
+  return parameters.filter(p => !hiddenParametersSlugSet.has(p.slug));
+}
diff --git a/frontend/src/metabase/parameters/utils/ui.unit.spec.js b/frontend/src/metabase/parameters/utils/ui.unit.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..8155721214b4abd20280d2412b873b440345d203
--- /dev/null
+++ b/frontend/src/metabase/parameters/utils/ui.unit.spec.js
@@ -0,0 +1,67 @@
+import {
+  getParameterIconName,
+  buildHiddenParametersSlugSet,
+  getVisibleParameters,
+} from "./ui";
+
+describe("parameters/utils/ui", () => {
+  describe("getParameterIconName", () => {
+    it("should return an icon name for the given parameter", () => {
+      expect(getParameterIconName({ type: "category" })).toEqual("string");
+      expect(getParameterIconName({ type: "date/single" })).toEqual("calendar");
+    });
+
+    it("should safely default", () => {
+      expect(getParameterIconName({ type: "???" })).toEqual("label");
+    });
+  });
+
+  describe("buildHiddenParametersSlugSet", () => {
+    it("should turn the given string of slugs separated by commas into a set of slug strings", () => {
+      expect(buildHiddenParametersSlugSet("a,b,c")).toEqual(
+        new Set(["a", "b", "c"]),
+      );
+    });
+
+    it("should return an empty set for any input that is not a string", () => {
+      expect(buildHiddenParametersSlugSet(undefined)).toEqual(new Set());
+      expect(buildHiddenParametersSlugSet(111111)).toEqual(new Set());
+    });
+  });
+
+  describe("getVisibleParameters", () => {
+    const parameters = [
+      {
+        id: 1,
+        slug: "foo",
+      },
+      {
+        id: 2,
+        slug: "bar",
+      },
+      {
+        id: 3,
+        slug: "baz",
+      },
+      {
+        id: 4,
+        slug: "qux",
+      },
+    ];
+
+    const hiddenParameterSlugs = "bar,baz";
+
+    it("should return the parameters that are not hidden", () => {
+      expect(getVisibleParameters(parameters, hiddenParameterSlugs)).toEqual([
+        {
+          id: 1,
+          slug: "foo",
+        },
+        {
+          id: 4,
+          slug: "qux",
+        },
+      ]);
+    });
+  });
+});
diff --git a/frontend/src/metabase/public/containers/PublicQuestion.jsx b/frontend/src/metabase/public/containers/PublicQuestion.jsx
index b1fa133682d5c4e9f18632f04c3225380ddaa45e..edf5da38333e42619d8ffdff7de2eb62d35d6acb 100644
--- a/frontend/src/metabase/public/containers/PublicQuestion.jsx
+++ b/frontend/src/metabase/public/containers/PublicQuestion.jsx
@@ -17,11 +17,11 @@ import {
   getParameterValuesBySlug,
   getParameterValuesByIdFromQueryParams,
 } from "metabase/parameters/utils/parameter-values";
+import { applyParameters } from "metabase/meta/Card";
 import {
   getParametersFromCard,
   getValueAndFieldIdPopulatedParametersFromCard,
-  applyParameters,
-} from "metabase/meta/Card";
+} from "metabase/parameters/utils/cards";
 
 import {
   PublicApi,
diff --git a/frontend/src/metabase/query_builder/actions.js b/frontend/src/metabase/query_builder/actions.js
index 508b40a4014fce51be1db65aa7331087526330a6..32c2474e798e1c01cb146ed398d79543b1334965 100644
--- a/frontend/src/metabase/query_builder/actions.js
+++ b/frontend/src/metabase/query_builder/actions.js
@@ -29,11 +29,9 @@ import Utils from "metabase/lib/utils";
 import { defer } from "metabase/lib/promise";
 import Question from "metabase-lib/lib/Question";
 import { FieldDimension } from "metabase-lib/lib/Dimension";
-import {
-  cardIsEquivalent,
-  cardQueryIsEquivalent,
-  getValueAndFieldIdPopulatedParametersFromCard,
-} from "metabase/meta/Card";
+import { cardIsEquivalent, cardQueryIsEquivalent } from "metabase/meta/Card";
+import { getValueAndFieldIdPopulatedParametersFromCard } from "metabase/parameters/utils/cards";
+
 import { getParameterValuesByIdFromQueryParams } from "metabase/parameters/utils/parameter-values";
 import { normalize } from "cljs/metabase.mbql.js";
 
diff --git a/frontend/src/metabase/query_builder/containers/QuestionEmbedWidget.jsx b/frontend/src/metabase/query_builder/containers/QuestionEmbedWidget.jsx
index 15f4b3bd381efd2bb6a35725f05d5c4fae0961b5..98f8f6c0a4a88309b8ce71e3dd412866bc325da4 100644
--- a/frontend/src/metabase/query_builder/containers/QuestionEmbedWidget.jsx
+++ b/frontend/src/metabase/query_builder/containers/QuestionEmbedWidget.jsx
@@ -11,8 +11,8 @@ import EmbedModalContent from "metabase/public/components/widgets/EmbedModalCont
 import * as Urls from "metabase/lib/urls";
 import MetabaseSettings from "metabase/lib/settings";
 import * as MetabaseAnalytics from "metabase/lib/analytics";
+import { getParametersFromCard } from "metabase/parameters/utils/cards";
 
-import { getParametersFromCard } from "metabase/meta/Card";
 import {
   createPublicLink,
   deletePublicLink,
diff --git a/frontend/src/metabase/query_builder/selectors.js b/frontend/src/metabase/query_builder/selectors.js
index c0312d7f37404318930d9598088584377e4afeb9..a12fd8b387bd14aac17dd7f1610a1872b992a022 100644
--- a/frontend/src/metabase/query_builder/selectors.js
+++ b/frontend/src/metabase/query_builder/selectors.js
@@ -13,7 +13,7 @@ import {
   getVisualizationTransformed,
 } from "metabase/visualizations";
 import { getComputedSettingsForSeries } from "metabase/visualizations/lib/settings/visualization";
-import { getValueAndFieldIdPopulatedParametersFromCard } from "metabase/meta/Card";
+import { getValueAndFieldIdPopulatedParametersFromCard } from "metabase/parameters/utils/cards";
 import { normalizeParameterValue } from "metabase/parameters/utils/parameter-values";
 
 import Utils from "metabase/lib/utils";
diff --git a/src/metabase/api/embed.clj b/src/metabase/api/embed.clj
index fe5a2d99ea69d380c5dd3a502e1eb092f64d0949..6b65eaabffe50c2164d222eacd46322e2da6bc3e 100644
--- a/src/metabase/api/embed.clj
+++ b/src/metabase/api/embed.clj
@@ -130,7 +130,7 @@
 (defn- template-tag-parameters
   "Transforms native query's `template-tags` into `parameters`."
   [card]
-  ;; NOTE: this should mirror `getTemplateTagParameters` in frontend/src/metabase/meta/Parameter.js
+  ;; NOTE: this should mirror `getTemplateTagParameters` in frontend/src/metabase/parameters/utils/cards.js
   (for [[_ {tag-type :type, widget-type :widget-type, :as tag}] (get-in card [:dataset_query :native :template-tags])
         :when                         (and tag-type
                                            (or widget-type (not= tag-type :dimension)))]