diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart
index 9197588468ab0276b07a408a58e45d407bd65385..416eebdb143589ca6e9ec943196665700f27b778 100644
--- a/packages/flutter/lib/src/material/time_picker.dart
+++ b/packages/flutter/lib/src/material/time_picker.dart
@@ -250,81 +250,89 @@ class _TimePickerHeader extends StatelessWidget {
     ).timeOfDayFormat(alwaysUse24HourFormat: _TimePickerModel.use24HourFormatOf(context));
 
     final _HourDialType hourDialType = _TimePickerModel.hourDialTypeOf(context);
-    switch (_TimePickerModel.orientationOf(context)) {
-      case Orientation.portrait:
-        return Column(
-          crossAxisAlignment: CrossAxisAlignment.start,
-          children: <Widget>[
-            Padding(
-              padding: EdgeInsetsDirectional.only(
-                bottom: _TimePickerModel.useMaterial3Of(context) ? 20 : 24,
-              ),
-              child: Text(
-                helpText,
-                style:
-                    _TimePickerModel.themeOf(context).helpTextStyle ??
-                    _TimePickerModel.defaultThemeOf(context).helpTextStyle,
+    final RenderObjectWidget orientationSpecificHeader = switch (_TimePickerModel.orientationOf(
+      context,
+    )) {
+      Orientation.portrait => Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: <Widget>[
+          Padding(
+            padding: EdgeInsetsDirectional.only(
+              bottom: _TimePickerModel.useMaterial3Of(context) ? 20 : 24,
+            ),
+            child: Text(
+              helpText,
+              style:
+                  _TimePickerModel.themeOf(context).helpTextStyle ??
+                  _TimePickerModel.defaultThemeOf(context).helpTextStyle,
+            ),
+          ),
+          Row(
+            textDirection:
+                timeOfDayFormat == TimeOfDayFormat.a_space_h_colon_mm
+                    ? TextDirection.rtl
+                    : TextDirection.ltr,
+            spacing: 12,
+            children: <Widget>[
+              Expanded(
+                child: Row(
+                  // Hour/minutes should not change positions in RTL locales.
+                  textDirection: TextDirection.ltr,
+                  children: <Widget>[
+                    const Expanded(child: _HourControl()),
+                    _TimeSelectorSeparator(timeOfDayFormat: timeOfDayFormat),
+                    const Expanded(child: _MinuteControl()),
+                  ],
+                ),
               ),
+              if (hourDialType == _HourDialType.twelveHour) const _DayPeriodControl(),
+            ],
+          ),
+        ],
+      ),
+      Orientation.landscape => SizedBox(
+        width: _kTimePickerHeaderLandscapeWidth,
+        child: Stack(
+          children: <Widget>[
+            Text(
+              helpText,
+              style:
+                  _TimePickerModel.themeOf(context).helpTextStyle ??
+                  _TimePickerModel.defaultThemeOf(context).helpTextStyle,
             ),
-            Row(
-              textDirection:
+            Column(
+              verticalDirection:
                   timeOfDayFormat == TimeOfDayFormat.a_space_h_colon_mm
-                      ? TextDirection.rtl
-                      : TextDirection.ltr,
+                      ? VerticalDirection.up
+                      : VerticalDirection.down,
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.start,
               spacing: 12,
               children: <Widget>[
-                Expanded(
-                  child: Row(
-                    // Hour/minutes should not change positions in RTL locales.
-                    textDirection: TextDirection.ltr,
-                    children: <Widget>[
-                      const Expanded(child: _HourControl()),
-                      _TimeSelectorSeparator(timeOfDayFormat: timeOfDayFormat),
-                      const Expanded(child: _MinuteControl()),
-                    ],
-                  ),
+                Row(
+                  // Hour/minutes should not change positions in RTL locales.
+                  textDirection: TextDirection.ltr,
+                  children: <Widget>[
+                    const Expanded(child: _HourControl()),
+                    _TimeSelectorSeparator(timeOfDayFormat: timeOfDayFormat),
+                    const Expanded(child: _MinuteControl()),
+                  ],
                 ),
                 if (hourDialType == _HourDialType.twelveHour) const _DayPeriodControl(),
               ],
             ),
           ],
-        );
-      case Orientation.landscape:
-        return SizedBox(
-          width: _kTimePickerHeaderLandscapeWidth,
-          child: Stack(
-            children: <Widget>[
-              Text(
-                helpText,
-                style:
-                    _TimePickerModel.themeOf(context).helpTextStyle ??
-                    _TimePickerModel.defaultThemeOf(context).helpTextStyle,
-              ),
-              Column(
-                verticalDirection:
-                    timeOfDayFormat == TimeOfDayFormat.a_space_h_colon_mm
-                        ? VerticalDirection.up
-                        : VerticalDirection.down,
-                mainAxisAlignment: MainAxisAlignment.center,
-                crossAxisAlignment: CrossAxisAlignment.start,
-                spacing: 12,
-                children: <Widget>[
-                  Row(
-                    // Hour/minutes should not change positions in RTL locales.
-                    textDirection: TextDirection.ltr,
-                    children: <Widget>[
-                      const Expanded(child: _HourControl()),
-                      _TimeSelectorSeparator(timeOfDayFormat: timeOfDayFormat),
-                      const Expanded(child: _MinuteControl()),
-                    ],
-                  ),
-                  if (hourDialType == _HourDialType.twelveHour) const _DayPeriodControl(),
-                ],
-              ),
-            ],
-          ),
-        );
-    }
+        ),
+      ),
+    };
+
+    return Semantics(
+      label: MaterialLocalizations.of(context).formatTimeOfDay(
+        _TimePickerModel.selectedTimeOf(context),
+        alwaysUse24HourFormat: MediaQuery.alwaysUse24HourFormatOf(context),
+      ),
+      child: orientationSpecificHeader,
+    );
   }
 }
 
@@ -443,11 +451,7 @@ class _HourControl extends StatelessWidget {
       child: _HourMinuteControl(
         isSelected: _TimePickerModel.hourMinuteModeOf(context) == _HourMinuteMode.hour,
         text: formattedHour,
-        onTap:
-            Feedback.wrapForTap(
-              () => _TimePickerModel.setHourMinuteMode(context, _HourMinuteMode.hour),
-              context,
-            )!,
+        onTap: () => _TimePickerModel.setHourMinuteMode(context, _HourMinuteMode.hour),
         onDoubleTap:
             _TimePickerModel.of(context, _TimePickerAspect.onHourDoubleTapped).onHourDoubleTapped,
       ),
@@ -559,11 +563,7 @@ class _MinuteControl extends StatelessWidget {
       child: _HourMinuteControl(
         isSelected: _TimePickerModel.hourMinuteModeOf(context) == _HourMinuteMode.minute,
         text: formattedMinute,
-        onTap:
-            Feedback.wrapForTap(
-              () => _TimePickerModel.setHourMinuteMode(context, _HourMinuteMode.minute),
-              context,
-            )!,
+        onTap: () => _TimePickerModel.setHourMinuteMode(context, _HourMinuteMode.minute),
         onDoubleTap:
             _TimePickerModel.of(
               context,
@@ -597,19 +597,6 @@ class _DayPeriodControl extends StatelessWidget {
     if (selectedTime.period == DayPeriod.am) {
       return;
     }
-    switch (Theme.of(context).platform) {
-      case TargetPlatform.android:
-      case TargetPlatform.fuchsia:
-      case TargetPlatform.linux:
-      case TargetPlatform.windows:
-        _announceToAccessibility(
-          context,
-          MaterialLocalizations.of(context).anteMeridiemAbbreviation,
-        );
-      case TargetPlatform.iOS:
-      case TargetPlatform.macOS:
-        break;
-    }
     _togglePeriod(context);
   }
 
@@ -618,19 +605,6 @@ class _DayPeriodControl extends StatelessWidget {
     if (selectedTime.period == DayPeriod.pm) {
       return;
     }
-    switch (Theme.of(context).platform) {
-      case TargetPlatform.android:
-      case TargetPlatform.fuchsia:
-      case TargetPlatform.linux:
-      case TargetPlatform.windows:
-        _announceToAccessibility(
-          context,
-          MaterialLocalizations.of(context).postMeridiemAbbreviation,
-        );
-      case TargetPlatform.iOS:
-      case TargetPlatform.macOS:
-        break;
-    }
     _togglePeriod(context);
   }
 
@@ -758,7 +732,7 @@ class _AmPmButton extends StatelessWidget {
     return Material(
       color: resolvedBackgroundColor,
       child: InkWell(
-        onTap: Feedback.wrapForTap(onPressed, context),
+        onTap: onPressed,
         child: Semantics(
           checked: selected,
           inMutuallyExclusiveGroup: true,
@@ -1328,18 +1302,9 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
     _center = box.size.center(Offset.zero);
     _dialSize = box.size;
     _updateThetaForPan(roundMinutes: true);
-    final TimeOfDay newTime = _notifyOnChangedIfNeeded(roundMinutes: true);
+    _notifyOnChangedIfNeeded(roundMinutes: true);
     if (widget.hourMinuteMode == _HourMinuteMode.hour) {
-      switch (widget.hourDialType) {
-        case _HourDialType.twentyFourHour:
-        case _HourDialType.twentyFourHourDoubleRing:
-          _announceToAccessibility(context, localizations.formatDecimal(newTime.hour));
-        case _HourDialType.twelveHour:
-          _announceToAccessibility(context, localizations.formatDecimal(newTime.hourOfPeriod));
-      }
       widget.onHourSelected?.call();
-    } else {
-      _announceToAccessibility(context, localizations.formatDecimal(newTime.minute));
     }
     final TimeOfDay time = _getTimeForTheta(
       _theta.value,
@@ -1354,7 +1319,6 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
   }
 
   void _selectHour(int hour) {
-    _announceToAccessibility(context, localizations.formatDecimal(hour));
     final TimeOfDay time;
 
     TimeOfDay getAmPmTime() {
@@ -1387,7 +1351,6 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
   }
 
   void _selectMinute(int minute) {
-    _announceToAccessibility(context, localizations.formatDecimal(minute));
     final TimeOfDay time = TimeOfDay(hour: widget.selectedTime.hour, minute: minute);
     final double angle = _getThetaForTime(time);
     _thetaTween
@@ -2775,7 +2738,6 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin {
   );
   final RestorableBoolN _autofocusHour = RestorableBoolN(null);
   final RestorableBoolN _autofocusMinute = RestorableBoolN(null);
-  final RestorableBool _announcedInitialTime = RestorableBool(false);
   late final RestorableEnumN<Orientation> _orientation = RestorableEnumN<Orientation>(
     widget.orientation,
     values: Orientation.values,
@@ -2793,7 +2755,6 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin {
     _lastModeAnnounced.dispose();
     _autofocusHour.dispose();
     _autofocusMinute.dispose();
-    _announcedInitialTime.dispose();
     super.dispose();
   }
 
@@ -2801,8 +2762,6 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin {
   void didChangeDependencies() {
     super.didChangeDependencies();
     localizations = MaterialLocalizations.of(context);
-    _announceInitialTimeOnce();
-    _announceModeOnce();
   }
 
   @override
@@ -2829,7 +2788,6 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin {
     registerForRestoration(_lastModeAnnounced, 'last_mode_announced');
     registerForRestoration(_autofocusHour, 'autofocus_hour');
     registerForRestoration(_autofocusMinute, 'autofocus_minute');
-    registerForRestoration(_announcedInitialTime, 'announced_initial_time');
     registerForRestoration(_selectedTime, 'selected_time');
     registerForRestoration(_orientation, 'orientation');
   }
@@ -2855,7 +2813,6 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin {
     _vibrate();
     setState(() {
       _hourMinuteMode.value = mode;
-      _announceModeOnce();
     });
   }
 
@@ -2877,37 +2834,6 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin {
     });
   }
 
-  void _announceModeOnce() {
-    if (_lastModeAnnounced.value == _hourMinuteMode.value) {
-      // Already announced it.
-      return;
-    }
-
-    switch (_hourMinuteMode.value) {
-      case _HourMinuteMode.hour:
-        _announceToAccessibility(context, localizations.timePickerHourModeAnnouncement);
-      case _HourMinuteMode.minute:
-        _announceToAccessibility(context, localizations.timePickerMinuteModeAnnouncement);
-    }
-    _lastModeAnnounced.value = _hourMinuteMode.value;
-  }
-
-  void _announceInitialTimeOnce() {
-    if (_announcedInitialTime.value) {
-      return;
-    }
-
-    final MaterialLocalizations localizations = MaterialLocalizations.of(context);
-    _announceToAccessibility(
-      context,
-      localizations.formatTimeOfDay(
-        _selectedTime.value,
-        alwaysUse24HourFormat: MediaQuery.alwaysUse24HourFormatOf(context),
-      ),
-    );
-    _announcedInitialTime.value = true;
-  }
-
   void _handleTimeChanged(TimeOfDay value) {
     _vibrate();
     setState(() {
@@ -2969,17 +2895,24 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin {
         };
         final Widget dial = Padding(
           padding: dialPadding,
-          child: ExcludeSemantics(
-            child: SizedBox.fromSize(
-              size: defaultTheme.dialSize,
-              child: AspectRatio(
-                aspectRatio: 1,
-                child: _Dial(
-                  hourMinuteMode: _hourMinuteMode.value,
-                  hourDialType: hourMode,
-                  selectedTime: _selectedTime.value,
-                  onChanged: _handleTimeChanged,
-                  onHourSelected: _handleHourSelected,
+          child: Semantics(
+            label: switch (_hourMinuteMode.value) {
+              _HourMinuteMode.hour => localizations.timePickerHourModeAnnouncement,
+              _HourMinuteMode.minute => localizations.timePickerMinuteModeAnnouncement,
+            },
+            liveRegion: true,
+            child: ExcludeSemantics(
+              child: SizedBox.fromSize(
+                size: defaultTheme.dialSize,
+                child: AspectRatio(
+                  aspectRatio: 1,
+                  child: _Dial(
+                    hourMinuteMode: _hourMinuteMode.value,
+                    hourDialType: hourMode,
+                    selectedTime: _selectedTime.value,
+                    onChanged: _handleTimeChanged,
+                    onHourSelected: _handleHourSelected,
+                  ),
                 ),
               ),
             ),
@@ -3233,10 +3166,6 @@ Future<TimeOfDay?> showTimePicker({
   );
 }
 
-void _announceToAccessibility(BuildContext context, String message) {
-  SemanticsService.announce(message, Directionality.of(context));
-}
-
 // An abstract base class for the M2 and M3 defaults below, so that their return
 // types can be non-nullable.
 abstract class _TimePickerDefaults extends TimePickerThemeData {
diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart
index 5dba36d33da3cc54452cc92188a991b80ad792fa..88474d1ba7797dd6310b2b3a0bfd4f7eda15ded4 100644
--- a/packages/flutter/test/material/time_picker_test.dart
+++ b/packages/flutter/test/material/time_picker_test.dart
@@ -2211,6 +2211,77 @@ void main() {
     expect(paragraph.text.style!.fontSize, 56.0);
   });
 
+  testWidgets('provides semantics information for hour/minute mode announcement', (
+    WidgetTester tester,
+  ) async {
+    final SemanticsTester semantics = SemanticsTester(tester);
+    await mediaQueryBoilerplate(tester, materialType: MaterialType.material3);
+
+    final MaterialLocalizations localizations = MaterialLocalizations.of(
+      tester.element(find.byType(TimePickerDialog)),
+    );
+    final Finder semanticsFinder = find.bySemanticsLabel(
+      localizations.timePickerHourModeAnnouncement,
+    );
+
+    final SemanticsNode semanticsNode = tester.getSemantics(semanticsFinder);
+    expect(
+      semanticsNode.label,
+      localizations.timePickerHourModeAnnouncement,
+      reason: 'Label should announce hour mode initially',
+    );
+    expect(
+      semanticsNode.hasFlag(SemanticsFlag.isLiveRegion),
+      isTrue,
+      reason: 'Node should be a live region to announce changes',
+    );
+
+    // --- Switch to minute mode ---
+    final Finder minuteControlInkWell = find.descendant(
+      of: _minuteControl,
+      matching: find.byType(InkWell),
+    );
+    expect(minuteControlInkWell, findsOneWidget, reason: 'Minute control should exist');
+    await tester.tap(minuteControlInkWell);
+    await tester.pumpAndSettle();
+
+    // Get the updated node properties
+    expect(
+      semanticsNode.label,
+      localizations.timePickerMinuteModeAnnouncement,
+      reason: 'Label should announce minute mode after switching',
+    );
+
+    semantics.dispose();
+  });
+
+  testWidgets('provides semantics information for the header (selected time)', (
+    WidgetTester tester,
+  ) async {
+    final SemanticsTester semantics = SemanticsTester(tester);
+    const TimeOfDay initialTime = TimeOfDay(hour: 7, minute: 15);
+
+    await mediaQueryBoilerplate(
+      tester,
+      initialTime: initialTime,
+      materialType: MaterialType.material3,
+    );
+
+    final MaterialLocalizations localizations = MaterialLocalizations.of(
+      tester.element(find.byType(TimePickerDialog)),
+    );
+    final String expectedLabel12Hour = localizations.formatTimeOfDay(initialTime);
+    final String expectedHelpText = localizations.timePickerDialHelpText;
+
+    expect(
+      semantics,
+      includesNodeWith(label: '$expectedLabel12Hour\n$expectedHelpText'),
+      reason: 'Header should have semantics label: $expectedLabel12Hour (12-hour)',
+    );
+
+    semantics.dispose();
+  });
+
   // This is a regression test for https://github.com/flutter/flutter/issues/153549.
   testWidgets('Time picker hour minute does not resize on error', (WidgetTester tester) async {
     await startPicker(entryMode: TimePickerEntryMode.input, tester, (TimeOfDay? value) {});