diff --git a/src/metabase/api/public.clj b/src/metabase/api/public.clj
index 9ca248b0387e3b4157eed84a51df492ee9107b23..cf662629c3181a2a8beac0ecdbe6830bdc54f92d 100644
--- a/src/metabase/api/public.clj
+++ b/src/metabase/api/public.clj
@@ -127,7 +127,7 @@
      {:error (tru "An error occurred while running the query.")})))
 
 (defn- process-query-for-card-with-id-run-fn
-  "Create the `:run` function used for [[process-query-for-card-with-id]] and [[process-query-for-dashcard]]."
+  "Create the `:make-run` function used for [[process-query-for-card-with-id]] and [[process-query-for-dashcard]]."
   [qp export-format]
   (fn run [query info]
     (qp.streaming/streaming-response [rff export-format (u/slugify (:card-name info))]
@@ -153,7 +153,8 @@
     (m/mapply qp.card/process-query-for-card card-id export-format
               :parameters parameters
               :context    :public-question
-              :run        (process-query-for-card-with-id-run-fn qp export-format)
+              :qp         qp
+              :make-run   process-query-for-card-with-id-run-fn
               options)))
 
 (defn ^:private process-query-for-card-with-public-uuid
@@ -267,7 +268,7 @@
                                    (string? parameters) (json/parse-string keyword))
                   :export-format export-format
                   :qp            qp
-                  :run           (process-query-for-card-with-id-run-fn qp export-format)})]
+                  :make-run      process-query-for-card-with-id-run-fn})]
     ;; Run this query with full superuser perms. We don't want the various perms checks failing because there are no
     ;; current user perms; if this Dashcard is public you're by definition allowed to run it without a perms check
     ;; anyway
diff --git a/src/metabase/pulse/util.clj b/src/metabase/pulse/util.clj
index 6d830cfa588b3ff1629a83980de5f9d0d4429fff..e409f8b6326c939b886970d2bc2c5ef5cb7c3467 100644
--- a/src/metabase/pulse/util.clj
+++ b/src/metabase/pulse/util.clj
@@ -74,17 +74,19 @@
                                           :dashcard dashcard
                                           :type     :card
                                           :result   (qp.dashboard/process-query-for-dashcard
-                                                     :dashboard-id  dashboard-id
-                                                     :card-id       card-id
-                                                     :dashcard-id   (u/the-id dashcard)
-                                                     :context       :dashboard-subscription
-                                                     :export-format :api
-                                                     :parameters    parameters
-                                                     :middleware    {:process-viz-settings? true
-                                                                     :js-int-to-string?     false}
-                                                     :run           (^:once fn* [query info]
-                                                                     (qp/process-query
-                                                                      (qp/userland-query-with-default-constraints query info))))})
+                                                      :dashboard-id  dashboard-id
+                                                      :card-id       card-id
+                                                      :dashcard-id   (u/the-id dashcard)
+                                                      :context       :dashboard-subscription
+                                                      :export-format :api
+                                                      :parameters    parameters
+                                                      :middleware    {:process-viz-settings? true
+                                                                      :js-int-to-string?     false}
+                                                      :make-run      (fn make-run [qp _export-format]
+                                                                       (^:once fn* [query info]
+                                                                               (qp
+                                                                                 (qp/userland-query-with-default-constraints query info)
+                                                                                 nil))))})
           result                       (result-fn card-id)
           series-results               (map (comp result-fn :id) multi-cards)]
       (when-not (and (get-in dashcard [:visualization_settings :card.hide_empty])
diff --git a/src/metabase/query_processor/card.clj b/src/metabase/query_processor/card.clj
index 61b3a2c3deb06c65ef22f93793b860a88f914ada..87cda35bb8fcd450c0ad2032e44b21b6b068dc8d 100644
--- a/src/metabase/query_processor/card.clj
+++ b/src/metabase/query_processor/card.clj
@@ -166,11 +166,11 @@
 (mu/defn process-query-for-card-default-qp :- :some
   "Default value of the `:qp` option for [[process-query-for-card]]."
   [query :- ::qp.schema/query
-   rff   :- ::qp.schema/rff]
+   rff   :- [:maybe ::qp.schema/rff]]
   (qp/process-query (qp/userland-query query) rff))
 
-(defn- process-query-for-card-default-run-fn
-  "Create the default `:run` function for [[process-query-for-card]]."
+(defn process-query-for-card-default-run-fn
+  "Create the default `:make-run` function for [[process-query-for-card]]."
   [qp export-format]
   (^:once fn* [query info]
    (qp.streaming/streaming-response [rff export-format (u/slugify (:card-name info))]
@@ -179,10 +179,14 @@
 (mu/defn process-query-for-card
   "Run the query for Card with `parameters` and `constraints`. By default, returns results in a
   `metabase.async.streaming_response.StreamingResponse` (see [[metabase.async.streaming-response]]) that should be
-  returned as the result of an API endpoint fn, but you can return something different by passing a different `:run`
-  option. `:run` has a signature
+  returned as the result of an API endpoint fn, but you can return something different by passing a different `:make-run`
+  option. `:make-run` has a signature.
 
-    (run query info) => result
+    (make-run qp export-format) => (fn run [query info])
+
+  The produced `run` fn has a signature, it should use the qp in to produce the results.
+
+    (run query info) => results
 
   Will throw an Exception if preconditions (such as read perms) are not met *before* returning the
   `StreamingResponse`.
@@ -192,13 +196,12 @@
   options."
   [card-id :- ::lib.schema.id/card
    export-format
-   & {:keys [parameters constraints context dashboard-id dashcard-id middleware qp run ignore-cache]
+   & {:keys [parameters constraints context dashboard-id dashcard-id middleware qp make-run ignore-cache]
       :or   {constraints (qp.constraints/default-query-constraints)
              context     :question
-             qp          process-query-for-card-default-qp
-             ;; param `run` can be used to control how the query is ran, e.g. if you need to customize the `context`
+             ;; param `make-run` can be used to control how the query is ran, e.g. if you need to customize the `context`
              ;; passed to the QP
-             run         (process-query-for-card-default-run-fn qp export-format)}}]
+             make-run    process-query-for-card-default-run-fn}}]
   {:pre [(int? card-id) (u/maybe? sequential? parameters)]}
   (let [dash-viz (when (and (not= context :question)
                             dashcard-id)
@@ -207,12 +210,17 @@
                                                  :type :result_metadata :visualization_settings :display
                                                  :cache_invalidated_at]
                                                 :id card-id))
+        ;; We need to check this here because dashcards don't get selected until this point
+        qp       (if (= :pivot (:display card))
+                   qp.pivot/run-pivot-query
+                   (or qp process-query-for-card-default-qp))
+        runner   (make-run qp export-format)
         query    (-> (query-for-card card parameters constraints middleware {:dashboard-id dashboard-id})
                      (update :viz-settings (fn [viz] (merge viz dash-viz)))
                      (update :middleware (fn [middleware]
                                            (merge
-                                            {:js-int-to-string? true, :ignore-cached-results? ignore-cache}
-                                            middleware))))
+                                             {:js-int-to-string? true, :ignore-cached-results? ignore-cache}
+                                             middleware))))
         info     (cond-> {:executed-by            api/*current-user-id*
                           :context                context
                           :card-id                card-id
@@ -226,7 +234,4 @@
     (log/tracef "Running query for Card %d:\n%s" card-id
                 (u/pprint-to-str query))
     (binding [qp.perms/*card-id* card-id]
-      (let [run (if (= :pivot (:display card))
-                  (process-query-for-card-default-run-fn qp.pivot/run-pivot-query export-format)
-                  run)]
-        (run query info)))))
+      (runner query info))))
diff --git a/src/metabase/query_processor/dashboard.clj b/src/metabase/query_processor/dashboard.clj
index 568a8a47b5b645e23725b6953bfc02767bafd559..f5f00762aae93b07c63edf3b67132bb8cb267278 100644
--- a/src/metabase/query_processor/dashboard.clj
+++ b/src/metabase/query_processor/dashboard.clj
@@ -163,7 +163,7 @@
 (defn process-query-for-dashcard
   "Like [[metabase.query-processor.card/process-query-for-card]], but runs the query for a `DashboardCard` with
   `parameters` and `constraints`. By default, returns a `metabase.async.streaming_response.StreamingResponse` (see
-  [[metabase.async.streaming-response]]), but this may vary if you pass in a different `:run` function. Will throw an
+  [[metabase.async.streaming-response]]), but this may vary if you pass in a different `:make-run` function. Will throw an
   Exception if preconditions such as proper permissions are not met *before* returning the `StreamingResponse`.
 
   See [[metabase.query-processor.card/process-query-for-card]] for more information about the various parameters."
diff --git a/test/metabase/api/card_test.clj b/test/metabase/api/card_test.clj
index a615361ba4f3dae9001f897c077fff1961a4845b..3246e56510031624012a9dffcc6b5c781c3646c7 100644
--- a/test/metabase/api/card_test.clj
+++ b/test/metabase/api/card_test.clj
@@ -2381,8 +2381,8 @@
       (let [orig qp.card/process-query-for-card]
         (with-redefs [qp.card/process-query-for-card (fn [card-id export-format & options]
                                                        (apply orig card-id export-format
-                                                              :run (fn [{:keys [constraints]} _]
-                                                                     {:constraints constraints})
+                                                              :make-run (constantly (fn [{:keys [constraints]} _]
+                                                                                      {:constraints constraints}))
                                                               options))]
           (testing "Sanity check: this CSV download should not be subject to C O N S T R A I N T S"
             (is (= {:constraints nil}
diff --git a/test/metabase/query_processor/card_test.clj b/test/metabase/query_processor/card_test.clj
index 2cab76d56094e30787801166929adb59850c0f44..2db499c78e5acdcc4c3c25b5a23ef62cfe93c022 100644
--- a/test/metabase/query_processor/card_test.clj
+++ b/test/metabase/query_processor/card_test.clj
@@ -21,9 +21,10 @@
   ;; stuff doesn't belong in the Dashboard QP namespace
   (binding [api/*current-user-permissions-set* (atom #{"/"})]
     (qp.card/process-query-for-card
-     card-id :api
-     :run (fn [query info]
-            (qp/process-query (assoc query :info info))))))
+      card-id :api
+      :make-run (constantly
+                  (fn [query info]
+                    (qp/process-query (assoc query :info info)))))))
 
 (defn field-filter-query
   "A query with a Field Filter parameter"
@@ -170,6 +171,17 @@
       (is (= [[100]]
              (mt/rows (run-query-for-card card-id)))))))
 
+(deftest ^:parallel pivot-tables-should-not-override-the-run-function
+  (testing "Pivot tables should not override the run function (#44160)"
+    (t2.with-temp/with-temp [:model/Card {card-id :id} {:dataset_query
+                                                        (mt/mbql-query venues
+                                                                       {:aggregation [[:count]]})
+                                                        :display :pivot}]
+      (let [result (run-query-for-card card-id)]
+        (is (=? {:status :completed}
+                result))
+        (is (= [[100]] (mt/rows result)))))))
+
 (deftest nested-query-permissions-test
   (testing "Should be able to run a Card with another Card as its source query with just perms for the former (#15131)"
     (mt/with-no-data-perms-for-all-users!
@@ -190,9 +202,10 @@
             (letfn [(process-query-for-card [card]
                       (qp.card/process-query-for-card
                        (u/the-id card) :api
-                       :run (fn [query info]
-                              (let [info (assoc info :query-hash (byte-array 0))]
-                                (qp/process-query (assoc query :info info))))))]
+                       :make-run (constantly
+                                   (fn [query info]
+                                     (let [info (assoc info :query-hash (byte-array 0))]
+                                       (qp/process-query (assoc query :info info)))))))]
               (testing "Should not be able to run the parent Card"
                 (is (not (mi/can-read? disallowed-collection)))
                 (is (not (mi/can-read? parent-card)))
diff --git a/test/metabase/query_processor/dashboard_test.clj b/test/metabase/query_processor/dashboard_test.clj
index ae5d8e3da8b8c994180c22586fa515529c1a28a9..3739eac91ed49fa6425a15982ff9f0a71c2a84e1 100644
--- a/test/metabase/query_processor/dashboard_test.clj
+++ b/test/metabase/query_processor/dashboard_test.clj
@@ -21,8 +21,9 @@
            :dashboard-id dashboard-id
            :card-id      card-id
            :dashcard-id  dashcard-id
-           :run          (fn run [query info]
-                           (qp/process-query (assoc query :info info)))
+           :make-run     (constantly
+                           (fn run [query info]
+                             (qp/process-query (assoc query :info info))))
            options)))
 
 (deftest resolve-parameters-validation-test