diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.test.ts b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.test.ts
index 98efdc71823..842ca2745ac 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.test.ts
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.test.ts
@@ -2,7 +2,14 @@ import { uniq } from 'lodash';
 
 import { TraceqlSearchScope } from '../dataquery.gen';
 
-import { generateQueryFromFilters, getUnscopedTags, getFilteredTags, getAllTags, getTagsByScope } from './utils';
+import {
+  generateQueryFromFilters,
+  getUnscopedTags,
+  getFilteredTags,
+  getAllTags,
+  getTagsByScope,
+  generateQueryFromAdHocFilters,
+} from './utils';
 
 describe('generateQueryFromFilters generates the correct query for', () => {
   it('an empty array', () => {
@@ -129,6 +136,31 @@ describe('generateQueryFromFilters generates the correct query for', () => {
   });
 });
 
+describe('generateQueryFromAdHocFilters generates the correct query for', () => {
+  it('an empty array', () => {
+    expect(generateQueryFromAdHocFilters([])).toBe('{}');
+  });
+
+  it('a filter with values', () => {
+    expect(generateQueryFromAdHocFilters([{ key: 'footag', operator: '=', value: 'foovalue' }])).toBe(
+      '{footag="foovalue"}'
+    );
+  });
+
+  it('two filters with values', () => {
+    expect(
+      generateQueryFromAdHocFilters([
+        { key: 'footag', operator: '=', value: 'foovalue' },
+        { key: 'bartag', operator: '=', value: 'barvalue' },
+      ])
+    ).toBe('{footag="foovalue" && bartag="barvalue"}');
+  });
+
+  it('a filter with intrinsic values', () => {
+    expect(generateQueryFromAdHocFilters([{ key: 'kind', operator: '=', value: 'server' }])).toBe('{kind=server}');
+  });
+});
+
 describe('gets correct tags', () => {
   it('for filtered tags when no tags supplied', () => {
     const tags = getFilteredTags(emptyTags, []);
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts
index 2cb2a79f3ec..378076ed50b 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts
@@ -1,6 +1,6 @@
 import { startCase, uniq } from 'lodash';
 
-import { SelectableValue } from '@grafana/data';
+import { AdHocVariableFilter, SelectableValue } from '@grafana/data';
 
 import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
 import { intrinsics } from '../traceql/traceql';
@@ -22,6 +22,7 @@ const valueHelper = (f: TraceqlFilter) => {
   }
   return f.value;
 };
+
 const scopeHelper = (f: TraceqlFilter) => {
   // Intrinsic fields don't have a scope
   if (intrinsics.find((t) => t === f.tag)) {
@@ -31,6 +32,7 @@ const scopeHelper = (f: TraceqlFilter) => {
     (f.scope === TraceqlSearchScope.Resource || f.scope === TraceqlSearchScope.Span ? f.scope?.toLowerCase() : '') + '.'
   );
 };
+
 const tagHelper = (f: TraceqlFilter, filters: TraceqlFilter[]) => {
   if (f.tag === 'duration') {
     const durationType = filters.find((f) => f.id === 'duration-type');
@@ -42,6 +44,20 @@ const tagHelper = (f: TraceqlFilter, filters: TraceqlFilter[]) => {
   return f.tag;
 };
 
+export const generateQueryFromAdHocFilters = (filters: AdHocVariableFilter[]) => {
+  return `{${filters
+    .filter((f) => f.key && f.operator && f.value)
+    .map((f) => `${f.key}${f.operator}${adHocValueHelper(f)}`)
+    .join(' && ')}}`;
+};
+
+const adHocValueHelper = (f: AdHocVariableFilter) => {
+  if (intrinsics.find((t) => t === f.key)) {
+    return f.value;
+  }
+  return `"${f.value}"`;
+};
+
 export const filterScopedTag = (f: TraceqlFilter) => {
   return scopeHelper(f) + f.tag;
 };
diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts
index 2f48b0abdd1..ff195732714 100644
--- a/public/app/plugins/datasource/tempo/datasource.ts
+++ b/public/app/plugins/datasource/tempo/datasource.ts
@@ -34,7 +34,7 @@ import {
 } from '@grafana/runtime';
 import { BarGaugeDisplayMode, TableCellDisplayMode, VariableFormatID } from '@grafana/schema';
 
-import { generateQueryFromFilters } from './SearchTraceQLEditor/utils';
+import { generateQueryFromAdHocFilters, generateQueryFromFilters } from './SearchTraceQLEditor/utils';
 import { TempoVariableQuery, TempoVariableQueryType } from './VariableQueryEditor';
 import { PrometheusDatasource, PromQuery } from './_importedDependencies/datasources/prometheus/types';
 import { TraceqlFilter, TraceqlSearchScope } from './dataquery.gen';
@@ -170,7 +170,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
     return tags.filter((tag) => tag !== undefined).map((tag) => ({ text: tag }));
   }
 
-  async labelValuesQuery(labelName?: string): Promise<Array<{ text: string }>> {
+  async labelValuesQuery(labelName?: string, query?: string): Promise<Array<{ text: string }>> {
     if (!labelName) {
       return [];
     }
@@ -192,7 +192,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
       // For V2, we need to send scope and tag name, e.g. `span.http.status_code`,
       // unless the tag has intrinsic scope
       const scopeAndTag = scope === 'intrinsic' ? labelName : `${scope}.${labelName}`;
-      options = await this.languageProvider.getOptionsV2(scopeAndTag);
+      options = await this.languageProvider.getOptionsV2(scopeAndTag, query);
     } catch {
       // For V1, the tag name (e.g. `http.status_code`) is enough
       options = await this.languageProvider.getOptionsV1(labelName);
@@ -217,7 +217,8 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
 
   // Allows to retrieve the list of tag values for ad-hoc filters
   getTagValues(options: DataSourceGetTagValuesOptions<TempoQuery>): Promise<Array<{ text: string }>> {
-    return this.labelValuesQuery(options.key.replace(/^(resource|span)\./, ''));
+    const query = generateQueryFromAdHocFilters(options.filters);
+    return this.labelValuesQuery(options.key.replace(/^(resource|span)\./, ''), query);
   }
 
   init = async () => {