diff --git a/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx
index 3e0a28021b649555ac5c86a83dbf41ce94660655..8c8d5e168e963b817b61e2e367ab511a30ad2240 100644
--- a/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx
+++ b/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx
@@ -32,6 +32,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -65,6 +66,7 @@ const CategoricalAreaChart = ({
   accessors = POSITIONAL_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   const colors = settings?.colors;
   const isVertical = data.length > 10;
@@ -138,9 +140,9 @@ const CategoricalAreaChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
       <LinePath
         data={data}
@@ -156,9 +158,9 @@ const CategoricalAreaChart = ({
         numTicks={data.length}
         stroke={palette.textLight}
         tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickComponent={props => <Text {...getXTickProps(props)} />}
-        tickLabelProps={() => getXTickLabelProps(layout, isVertical)}
+        tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx
index edb38de3b6cae61ae029bc001429f2e84028af00..b5231519c866d2d88f376d75ae99fe96a9320927 100644
--- a/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx
+++ b/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx
@@ -32,6 +32,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -64,6 +65,7 @@ const CategoricalBarChart = ({
   accessors = POSITIONAL_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   const colors = settings?.colors;
   const isVertical = data.length > 10;
@@ -142,9 +144,9 @@ const CategoricalBarChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
       <AxisBottom
         scale={xScale}
@@ -153,9 +155,9 @@ const CategoricalBarChart = ({
         numTicks={data.length}
         stroke={palette.textLight}
         tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickComponent={props => <Text {...getXTickProps(props)} />}
-        tickLabelProps={() => getXTickLabelProps(layout, isVertical)}
+        tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx
index ddc832c5afa548443ce1ff0464232812e30eb054..a6e46aa3027db66d79a4e407fe000d9dc634a162 100644
--- a/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx
+++ b/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx
@@ -32,6 +32,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -64,6 +65,7 @@ const CategoricalLineChart = ({
   accessors = POSITIONAL_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   const colors = settings?.colors;
   const isVertical = data.length > 10;
@@ -136,9 +138,9 @@ const CategoricalLineChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
       <AxisBottom
         scale={xScale}
@@ -147,9 +149,9 @@ const CategoricalLineChart = ({
         numTicks={data.length}
         stroke={palette.textLight}
         tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickComponent={props => <Text {...getXTickProps(props)} />}
-        tickLabelProps={() => getXTickLabelProps(layout, isVertical)}
+        tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx
index f4bc76fce4cdb42381dc19c702f4199b739ec46d..527be39e3f13055ea97d3fda03c3fa3f6ec4ccae 100644
--- a/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx
+++ b/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx
@@ -22,6 +22,7 @@ import {
   getWaterfallEntryColor,
 } from "metabase/static-viz/lib/waterfall";
 import { POSITIONAL_ACCESSORS } from "../../constants/accessors";
+import { getWaterfallColors } from "../../lib/colors";
 
 const propTypes = {
   data: PropTypes.array.isRequired,
@@ -39,6 +40,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -54,14 +56,6 @@ const layout = {
     size: 11,
     family: "Lato, sans-serif",
   },
-  colors: {
-    brand: "#509ee3",
-    textLight: "#b8bbc3",
-    textMedium: "#949aab",
-    waterfallTotal: "#4C5773",
-    waterfallPositive: "#88BF4D",
-    waterfallNegative: "#EF8C8C",
-  },
   barPadding: 0.2,
   labelFontWeight: 700,
   labelPadding: 12,
@@ -74,13 +68,13 @@ const CategoricalWaterfallChart = ({
   accessors = POSITIONAL_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   const entries = calculateWaterfallEntries(
     data,
     accessors,
     settings?.showTotal,
   );
-  const colors = settings?.colors;
   const isVertical = entries.length > 10;
   const xTickWidth = getXTickWidth(
     data,
@@ -100,7 +94,6 @@ const CategoricalWaterfallChart = ({
   const textBaseline = Math.floor(layout.font.size / 2);
   const leftLabel = labels?.left;
   const bottomLabel = !isVertical ? labels?.bottom : undefined;
-  const palette = { ...layout.colors, ...colors };
 
   const xScale = scaleBand({
     domain: entries.map(entry => entry.x),
@@ -119,7 +112,11 @@ const CategoricalWaterfallChart = ({
     const height = Math.abs(yScale(entry.start) - yScale(entry.end));
     const x = xScale(entry.x);
     const y = yScale(Math.max(entry.start, entry.end));
-    const fill = getWaterfallEntryColor(entry, palette);
+
+    const fill = getWaterfallEntryColor(
+      entry,
+      getWaterfallColors(settings?.colors, getColor),
+    );
 
     return { x, y, width, height, fill };
   };
@@ -158,9 +155,9 @@ const CategoricalWaterfallChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
 
       <AxisBottom
@@ -169,11 +166,11 @@ const CategoricalWaterfallChart = ({
         top={yMax + layout.margin.top}
         label={bottomLabel}
         numTicks={entries.length}
-        stroke={palette.textLight}
-        tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        stroke={getColor("text-light")}
+        tickStroke={getColor("text-light")}
+        labelProps={getLabelProps(layout, getColor)}
         tickComponent={props => <Text {...getXTickProps(props)} />}
-        tickLabelProps={() => getXTickLabelProps(layout, isVertical)}
+        tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx
index 947236dbfc57992903faca3f7874dfa06561fa3c..e3b6db5562332412fe3094afb9c1d51256491e11 100644
--- a/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx
+++ b/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx
@@ -30,6 +30,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -64,6 +65,7 @@ const TimeSeriesAreaChart = ({
   accessors = DATE_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   data = sortTimeSeries(data);
   const colors = settings?.colors;
@@ -119,9 +121,9 @@ const TimeSeriesAreaChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
       <AxisBottom
         scale={xScale}
@@ -130,9 +132,9 @@ const TimeSeriesAreaChart = ({
         numTicks={layout.numTicks}
         stroke={palette.textLight}
         tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatDate(value, settings?.x)}
-        tickLabelProps={() => getXTickLabelProps(layout)}
+        tickLabelProps={() => getXTickLabelProps(layout, false, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx
index 3c10908778ad2edd970bddb7c6f237a50b029507..158c65b93fe809eb540dd39c608387a591ce753e 100644
--- a/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx
+++ b/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx
@@ -30,6 +30,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -62,6 +63,7 @@ const TimeSeriesBarChart = ({
   accessors = DATE_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   data = sortTimeSeries(data);
   const colors = settings?.colors;
@@ -116,9 +118,9 @@ const TimeSeriesBarChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
       <AxisBottom
         scale={xScale}
@@ -127,9 +129,9 @@ const TimeSeriesBarChart = ({
         numTicks={layout.numTicks}
         stroke={palette.textLight}
         tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatDate(value, settings?.x)}
-        tickLabelProps={() => getXTickLabelProps(layout)}
+        tickLabelProps={() => getXTickLabelProps(layout, false, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx
index 32695e569d8d3239ae81ae8b79e8e0de59fe858c..7d720b3f8c86c9338ba967ec6788f8b407125693 100644
--- a/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx
+++ b/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx
@@ -30,6 +30,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -62,6 +63,7 @@ const TimeSeriesLineChart = ({
   accessors = DATE_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   data = sortTimeSeries(data);
   const colors = settings?.colors;
@@ -109,9 +111,9 @@ const TimeSeriesLineChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
       <AxisBottom
         scale={xScale}
@@ -120,9 +122,9 @@ const TimeSeriesLineChart = ({
         numTicks={layout.numTicks}
         stroke={palette.textLight}
         tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatDate(value, settings?.x)}
-        tickLabelProps={() => getXTickLabelProps(layout)}
+        tickLabelProps={() => getXTickLabelProps(layout, false, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx
index 1b5356e46c9aff9c130abebaa5d9d4d3d09007c3..1b9573821505b456b5bbc81bdc593980c8eaa534 100644
--- a/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx
+++ b/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx
@@ -20,6 +20,7 @@ import {
 } from "metabase/static-viz/lib/waterfall";
 import { sortTimeSeries } from "../../lib/sort";
 import { DATE_ACCESSORS } from "../../constants/accessors";
+import { getWaterfallColors } from "../../lib/colors";
 
 const propTypes = {
   data: PropTypes.array.isRequired,
@@ -37,6 +38,7 @@ const propTypes = {
     left: PropTypes.string,
     bottom: PropTypes.string,
   }),
+  getColor: PropTypes.func,
 };
 
 const layout = {
@@ -52,14 +54,6 @@ const layout = {
     size: 11,
     family: "Lato, sans-serif",
   },
-  colors: {
-    brand: "#509ee3",
-    textLight: "#b8bbc3",
-    textMedium: "#949aab",
-    waterfallTotal: "#4C5773",
-    waterfallPositive: "#88BF4D",
-    waterfallNegative: "#EF8C8C",
-  },
   numTicks: 4,
   barPadding: 0.2,
   labelFontWeight: 700,
@@ -72,9 +66,9 @@ const TimeSeriesWaterfallChart = ({
   accessors = DATE_ACCESSORS,
   settings,
   labels,
+  getColor,
 }) => {
   data = sortTimeSeries(data);
-  const colors = settings?.colors;
   const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size);
   const yLabelOffset = yTickWidth + layout.labelPadding;
   const xMin = yLabelOffset + layout.font.size * 1.5;
@@ -83,7 +77,6 @@ const TimeSeriesWaterfallChart = ({
   const innerWidth = xMax - xMin;
   const leftLabel = labels?.left;
   const bottomLabel = labels?.bottom;
-  const palette = { ...layout.colors, ...colors };
 
   const entries = calculateWaterfallEntries(
     data,
@@ -108,7 +101,10 @@ const TimeSeriesWaterfallChart = ({
     const height = Math.abs(yScale(entry.start) - yScale(entry.end));
     const x = xScale(entry.x);
     const y = yScale(Math.max(entry.start, entry.end));
-    const fill = getWaterfallEntryColor(entry, palette);
+    const fill = getWaterfallEntryColor(
+      entry,
+      getWaterfallColors(settings?.colors, getColor),
+    );
 
     return { x, y, width, height, fill };
   };
@@ -133,9 +129,9 @@ const TimeSeriesWaterfallChart = ({
         labelOffset={yLabelOffset}
         hideTicks
         hideAxisLine
-        labelProps={getLabelProps(layout)}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatNumber(value, settings?.y)}
-        tickLabelProps={() => getYTickLabelProps(layout)}
+        tickLabelProps={() => getYTickLabelProps(layout, getColor)}
       />
       <AxisBottom
         scale={xScale}
@@ -143,11 +139,11 @@ const TimeSeriesWaterfallChart = ({
         top={yMax + layout.margin.top}
         label={bottomLabel}
         numTicks={layout.numTicks}
-        stroke={palette.textLight}
-        tickStroke={palette.textLight}
-        labelProps={getLabelProps(layout)}
+        stroke={getColor("text-light")}
+        tickStroke={getColor("text-light")}
+        labelProps={getLabelProps(layout, getColor)}
         tickFormat={value => formatTimescaleWaterfallTick(value, settings)}
-        tickLabelProps={() => getXTickLabelProps(layout)}
+        tickLabelProps={() => getXTickLabelProps(layout, false, getColor)}
       />
     </svg>
   );
diff --git a/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx b/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx
index 4bd5e7603c9695875a6c27835c283e781d1c6515..318377e6a166fd760b7cb5503d634095730e0dc6 100644
--- a/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx
+++ b/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx
@@ -23,34 +23,38 @@ import LineAreaBarChart from "../../components/LineAreaBarChart";
 import { LINE_AREA_BAR_CHART_TYPE } from "../../components/LineAreaBarChart/constants";
 import Funnel from "../../components/FunnelChart";
 import { FUNNEL_CHART_TYPE } from "../../components/FunnelChart/constants";
+import { createColorGetter } from "metabase/static-viz/lib/colors";
 import { StaticChartProps } from "./types";
 
 const StaticChart = ({ type, options }: StaticChartProps) => {
+  const getColor = createColorGetter(options.colors);
+  const chartProps = { ...options, getColor };
+
   switch (type) {
     case CATEGORICAL_AREA_CHART_TYPE:
-      return <CategoricalAreaChart {...options} />;
+      return <CategoricalAreaChart {...chartProps} />;
     case CATEGORICAL_BAR_CHART_TYPE:
-      return <CategoricalBarChart {...options} />;
+      return <CategoricalBarChart {...chartProps} />;
     case CATEGORICAL_DONUT_CHART_TYPE:
-      return <CategoricalDonutChart {...options} />;
+      return <CategoricalDonutChart {...chartProps} />;
     case CATEGORICAL_LINE_CHART_TYPE:
-      return <CategoricalLineChart {...options} />;
+      return <CategoricalLineChart {...chartProps} />;
     case CATEGORICAL_WATERFALL_CHART_TYPE:
-      return <CategoricalWaterfallChart {...options} />;
+      return <CategoricalWaterfallChart {...chartProps} />;
     case TIME_SERIES_AREA_CHART_TYPE:
-      return <TimeSeriesAreaChart {...options} />;
+      return <TimeSeriesAreaChart {...chartProps} />;
     case TIME_SERIES_BAR_CHART_TYPE:
-      return <TimeSeriesBarChart {...options} />;
+      return <TimeSeriesBarChart {...chartProps} />;
     case TIME_SERIES_LINE_CHART_TYPE:
-      return <TimeSeriesLineChart {...options} />;
+      return <TimeSeriesLineChart {...chartProps} />;
     case TIME_SERIES_WATERFALL_CHART_TYPE:
-      return <TimeSeriesWaterfallChart {...options} />;
+      return <TimeSeriesWaterfallChart {...chartProps} />;
     case PROGRESS_BAR_TYPE:
-      return <ProgressBar {...options} />;
+      return <ProgressBar {...chartProps} />;
     case LINE_AREA_BAR_CHART_TYPE:
-      return <LineAreaBarChart {...options} />;
+      return <LineAreaBarChart {...chartProps} />;
     case FUNNEL_CHART_TYPE:
-      return <Funnel {...options} />;
+      return <Funnel {...chartProps} />;
   }
 };
 
diff --git a/frontend/src/metabase/static-viz/containers/StaticChart/types.ts b/frontend/src/metabase/static-viz/containers/StaticChart/types.ts
index 5104371c633645afb9a5140b67467cc279eded76..bf78b5a76bf649ad73d7227314194a6f0af8fbf9 100644
--- a/frontend/src/metabase/static-viz/containers/StaticChart/types.ts
+++ b/frontend/src/metabase/static-viz/containers/StaticChart/types.ts
@@ -1,3 +1,4 @@
+import { ColorPalette } from "metabase/lib/colors/types";
 import { STATIC_CHART_TYPES } from "./constants";
 
 type StaticChartType = typeof STATIC_CHART_TYPES[number];
@@ -5,4 +6,5 @@ type StaticChartType = typeof STATIC_CHART_TYPES[number];
 export interface StaticChartProps {
   type: StaticChartType;
   options: any;
+  colors?: ColorPalette;
 }
diff --git a/frontend/src/metabase/static-viz/lib/axes.js b/frontend/src/metabase/static-viz/lib/axes.js
index 747c5ef11dfb8d65c1b7f5b721e2a7faf692cabd..a6cf5f96ab600d6a6fde69a4883a2bf9cbb05a29 100644
--- a/frontend/src/metabase/static-viz/lib/axes.js
+++ b/frontend/src/metabase/static-viz/lib/axes.js
@@ -26,24 +26,24 @@ export const getYTickWidth = (data, accessors, settings, fontSize) => {
     .reduce((a, b) => Math.max(a, b), 0);
 };
 
-export const getXTickLabelProps = (layout, isVertical) => ({
+export const getXTickLabelProps = (layout, isVertical, getColor) => ({
   fontSize: layout.font.size,
   fontFamily: layout.font.family,
-  fill: layout.colors.textMedium,
+  fill: getColor("text-medium"),
   textAnchor: isVertical ? "start" : "middle",
 });
 
-export const getYTickLabelProps = layout => ({
+export const getYTickLabelProps = (layout, getColor) => ({
   fontSize: layout.font.size,
   fontFamily: layout.font.family,
-  fill: layout.colors.textMedium,
+  fill: getColor("text-medium"),
   textAnchor: "end",
 });
 
-export const getLabelProps = layout => ({
+export const getLabelProps = (layout, getColor) => ({
   fontWeight: layout.labelFontWeight,
   fontSize: layout.font.size,
   fontFamily: layout.font.family,
-  fill: layout.colors.textMedium,
+  fill: getColor("text-medium"),
   textAnchor: "middle",
 });
diff --git a/frontend/src/metabase/static-viz/lib/colors.ts b/frontend/src/metabase/static-viz/lib/colors.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4566ef8bf5578dc4b5c5a4ae77d5fe3d534ff614
--- /dev/null
+++ b/frontend/src/metabase/static-viz/lib/colors.ts
@@ -0,0 +1,29 @@
+import { colors, color } from "metabase/lib/colors/palette";
+import { ColorPalette } from "metabase/lib/colors/types";
+
+export type ColorGetter = (colorName: string) => string;
+
+export const createColorGetter = (
+  instanceColors: ColorPalette = {},
+): ColorGetter => {
+  const palette = { ...colors, ...instanceColors };
+
+  return (colorName: string) => color(colorName, palette);
+};
+
+export type WaterfallColors = {
+  waterfallTotal: string;
+  waterfallPositive: string;
+  waterfallNegative: string;
+};
+
+export const getWaterfallColors = (
+  colorSettings: Partial<WaterfallColors> = {},
+  getColor: ColorGetter,
+): WaterfallColors => {
+  return {
+    waterfallTotal: colorSettings.waterfallTotal ?? getColor("text-dark"),
+    waterfallPositive: colorSettings.waterfallPositive ?? getColor("accent1"),
+    waterfallNegative: colorSettings.waterfallNegative ?? getColor("accent3"),
+  };
+};
diff --git a/resources/frontend_shared/static_viz_interface.js b/resources/frontend_shared/static_viz_interface.js
index a664ba6aa76d76c5cbb6142b560ef410e0545367..97dc555c2aff50ee73e84c19628a37265d78bbb1 100644
--- a/resources/frontend_shared/static_viz_interface.js
+++ b/resources/frontend_shared/static_viz_interface.js
@@ -47,11 +47,12 @@ function combo_chart(series, settings, colors) {
   });
 }
 
-function timeseries_waterfall(data, labels, settings) {
+function timeseries_waterfall(data, labels, settings, instanceColors) {
   return StaticViz.RenderChart("timeseries/waterfall", {
     data: toJSArray(data),
     labels: toJSMap(labels),
     settings: JSON.parse(settings),
+    colors: JSON.parse(instanceColors),
   });
 }
 
@@ -93,11 +94,12 @@ function categorical_donut(rows, colors) {
   });
 }
 
-function categorical_waterfall(data, labels, settings) {
+function categorical_waterfall(data, labels, settings, instanceColors) {
   return StaticViz.RenderChart("categorical/waterfall", {
     data: toJSArray(data),
     labels: toJSMap(labels),
     settings: JSON.parse(settings),
+    colors: JSON.parse(instanceColors),
   });
 }
 
diff --git a/src/metabase/pulse/render/body.clj b/src/metabase/pulse/render/body.clj
index a03f555a09cb8c2a6988f4c75e1f14dd8487096c..240f6834c745ae0b91b5df36b65277ab4ee2bdbc 100644
--- a/src/metabase/pulse/render/body.clj
+++ b/src/metabase/pulse/render/body.clj
@@ -776,9 +776,9 @@
                          (:waterfall.show_total viz-settings))
         settings       (-> (->js-viz x-col y-col viz-settings)
                            (update :colors assoc
-                                   :waterfallTotal (or (:waterfall.total_color viz-settings) (nth colors 0))
-                                   :waterfallPositive (or (:waterfall.increase_color viz-settings) (nth colors 1))
-                                   :waterfallNegative (or (:waterfall.decrease_color viz-settings) (nth colors 2)))
+                                   :waterfallTotal (:waterfall.total_color viz-settings)
+                                   :waterfallPositive (:waterfall.increase_color viz-settings)
+                                   :waterfallNegative (:waterfall.decrease_color viz-settings))
                            (assoc :showTotal show-total))
         image-bundle   (image-bundle/make-image-bundle
                         render-type
diff --git a/src/metabase/pulse/render/js_svg.clj b/src/metabase/pulse/render/js_svg.clj
index 6014ce9b21b77d8c45b6286aeaa2262735324946..e74d3b3c7c873a5fc966a54bf4cda3a1698bb9cf 100644
--- a/src/metabase/pulse/render/js_svg.clj
+++ b/src/metabase/pulse/render/js_svg.clj
@@ -5,6 +5,7 @@
   `toJSMap` functions to turn Clojure's normal datastructures into js native structures."
   (:require [cheshire.core :as json]
             [clojure.string :as str]
+            [metabase.public-settings :as public-settings]
             [metabase.pulse.render.js-engine :as js])
   (:import [java.io ByteArrayInputStream ByteArrayOutputStream]
            java.nio.charset.StandardCharsets
@@ -115,7 +116,8 @@
   [rows labels settings]
   (let [svg-string (.asString (js/execute-fn-name @context "timeseries_waterfall" rows
                                                   (map (fn [[k v]] [(name k) v]) labels)
-                                                  (json/generate-string settings)))]
+                                                  (json/generate-string settings)
+                                                  (json/generate-string (public-settings/application-colors))))]
     (svg-string->bytes svg-string)))
 
 (defn funnel
@@ -174,7 +176,8 @@
   [rows labels settings]
   (let [svg-string (.asString (js/execute-fn-name @context "categorical_waterfall" rows
                                                   (map (fn [[k v]] [(name k) v]) labels)
-                                                  (json/generate-string settings)))]
+                                                  (json/generate-string settings)
+                                                  (json/generate-string (public-settings/application-colors))))]
     (svg-string->bytes svg-string)))
 
 (defn categorical-bar
diff --git a/test/metabase/pulse/render/js_svg_test.clj b/test/metabase/pulse/render/js_svg_test.clj
index eaea55d5d71e5bbf00ef0c0a10829ffa3bfe4298..6d4f7b493f8c0e1f4145ca7a4bb45842c925a872 100644
--- a/test/metabase/pulse/render/js_svg_test.clj
+++ b/test/metabase/pulse/render/js_svg_test.clj
@@ -9,6 +9,7 @@
             [clojure.set :as set]
             [clojure.spec.alpha :as s]
             [clojure.test :refer :all]
+            [metabase.public-settings :as public-settings]
             [metabase.pulse.render.js-engine :as js]
             [metabase.pulse.render.js-svg :as js-svg])
   (:import org.apache.batik.anim.dom.SVGOMDocument
@@ -175,7 +176,7 @@
     (testing "It returns bytes"
       (let [svg-bytes (js-svg/timelineseries-waterfall rows labels settings)]
         (is (bytes? svg-bytes))))
-    (let [svg-string (.asString (js/execute-fn-name @context "timeseries_waterfall" rows labels settings))]
+    (let [svg-string (.asString (js/execute-fn-name @context "timeseries_waterfall" rows labels settings (json/generate-string (public-settings/application-colors))))]
       (testing "it returns a valid svg string (no html in it)"
         (validate-svg-string :timelineseries-waterfall svg-string)))))
 
@@ -245,5 +246,5 @@
     (testing "It returns bytes"
       (let [svg-bytes (js-svg/categorical-waterfall rows labels {})]
         (is (bytes? svg-bytes))))
-    (let [svg-string (.asString ^Value (js/execute-fn-name @context "categorical_waterfall" rows labels settings))]
+    (let [svg-string (.asString ^Value (js/execute-fn-name @context "categorical_waterfall" rows labels settings (json/generate-string (public-settings/application-colors))))]
       (validate-svg-string :categorical/waterfall svg-string))))