diff --git a/Android.bp b/Android.bp
index 6b55cc9f5ea863882689d0354df1a8bf12dc9e8a..36799e4bbf8233b13ef122fa0b5313b370e60393 100644
--- a/Android.bp
+++ b/Android.bp
@@ -580,6 +580,7 @@ java_defaults {
     aidl: {
         generate_get_transaction_name: true,
         local_include_dirs: ["media/aidl"],
+        include_dirs: ["frameworks/av/aidl"],
     },
     dxflags: [
         "--core-library",
@@ -614,6 +615,7 @@ java_defaults {
         // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
         // in favor of an API stubs dependency in java_library "framework" below.
         "mimemap",
+        "av-types-aidl-java",
         "mediatranscoding_aidl_interface-java",
         "soundtrigger_middleware-aidl-java",
     ],
diff --git a/ApiDocs.bp b/ApiDocs.bp
index faa0e5dba9973d7e7b06c45da1935744b049f9a4..7ed7ec526686fbc833de44e1cdb29e651ddd0dad 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -86,6 +86,7 @@ stubs_defaults {
     // TODO(b/169090544): remove below aidl includes.
     aidl: {
         local_include_dirs: ["media/aidl"],
+        include_dirs: ["frameworks/av/aidl"],
     },
 }
 
@@ -157,6 +158,7 @@ doc_defaults {
     // TODO(b/169090544): remove below aidl includes.
     aidl: {
         local_include_dirs: ["media/aidl"],
+        include_dirs: ["frameworks/av/aidl"],
     },
 }
 
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 8090bec24fdb73f3870c1aeb4a5ca10e648cdf88..9ca3739d9a2664a507e1aa2ffabe05b34d9c31c7 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -57,6 +57,7 @@ stubs_defaults {
             "telephony/java",
             "media/aidl",
         ],
+        include_dirs: ["frameworks/av/aidl"],
     },
     // These are libs from framework-internal-utils that are required (i.e. being referenced)
     // from framework-non-updatable-sources. Add more here when there's a need.
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index df5e85edbc3055307fb875eb3bd1d16aa05daaf5..da69c6cbbb5c7ad91cf7fc4df7b44773da686642 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -520,11 +520,12 @@ public abstract class PlayerBase {
 
         @Override
         public void applyVolumeShaper(
-                @NonNull VolumeShaper.Configuration configuration,
-                @NonNull VolumeShaper.Operation operation) {
+                @NonNull VolumeShaperConfiguration configuration,
+                @NonNull VolumeShaperOperation operation) {
             final PlayerBase pb = mWeakPB.get();
             if (pb != null) {
-                pb.playerApplyVolumeShaper(configuration, operation);
+                pb.playerApplyVolumeShaper(VolumeShaper.Configuration.fromParcelable(configuration),
+                        VolumeShaper.Operation.fromParcelable(operation));
             }
         }
     }
diff --git a/media/java/android/media/PlayerProxy.java b/media/java/android/media/PlayerProxy.java
index 5f3997a50ce44bd0d351062d00ba7301d1feb2ee..ec391284b0b2e598b85cf4f9864662282b82a5be 100644
--- a/media/java/android/media/PlayerProxy.java
+++ b/media/java/android/media/PlayerProxy.java
@@ -143,7 +143,8 @@ public class PlayerProxy {
             @NonNull VolumeShaper.Configuration configuration,
             @NonNull VolumeShaper.Operation operation) {
         try {
-            mConf.getIPlayer().applyVolumeShaper(configuration, operation);
+            mConf.getIPlayer().applyVolumeShaper(configuration.toParcelable(),
+                    operation.toParcelable());
         } catch (NullPointerException|RemoteException e) {
             throw new IllegalStateException(
                     "No player to proxy for applyVolumeShaper operation,"
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index df8d08e8e846ab8c5924c24ef2881e389d3f0e9a..5bad6934f981abfdfd039a34ea1543b836af8c54 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
+import android.os.BadParcelableException;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -482,50 +483,62 @@ public final class VolumeShaper implements AutoCloseable {
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            // this needs to match the native VolumeShaper.Configuration parceling
-            dest.writeInt(mType);
-            dest.writeInt(mId);
+            VolumeShaperConfiguration parcelable = toParcelable();
+            parcelable.writeToParcel(dest, flags);
+        }
+
+        /** @hide */
+        public VolumeShaperConfiguration toParcelable() {
+            VolumeShaperConfiguration parcelable = new VolumeShaperConfiguration();
+            parcelable.type = typeToAidl(mType);
+            parcelable.id = mId;
             if (mType != TYPE_ID) {
-                dest.writeInt(mOptionFlags);
-                dest.writeDouble(mDurationMs);
-                // this needs to match the native Interpolator parceling
-                dest.writeInt(mInterpolatorType);
-                dest.writeFloat(0.f); // first slope (specifying for native side)
-                dest.writeFloat(0.f); // last slope (specifying for native side)
-                // mTimes and mVolumes should have the same length.
-                dest.writeInt(mTimes.length);
-                for (int i = 0; i < mTimes.length; ++i) {
-                    dest.writeFloat(mTimes[i]);
-                    dest.writeFloat(mVolumes[i]);
-                }
+                parcelable.optionFlags = optionFlagsToAidl(mOptionFlags);
+                parcelable.durationMs = mDurationMs;
+                parcelable.interpolatorConfig = toInterpolatorParcelable();
             }
+            return parcelable;
         }
 
-        public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Configuration> CREATOR
-                = new Parcelable.Creator<VolumeShaper.Configuration>() {
-            @Override
-            public VolumeShaper.Configuration createFromParcel(Parcel p) {
-                // this needs to match the native VolumeShaper.Configuration parceling
-                final int type = p.readInt();
-                final int id = p.readInt();
-                if (type == TYPE_ID) {
-                    return new VolumeShaper.Configuration(id);
-                } else {
-                    final int optionFlags = p.readInt();
-                    final double durationMs = p.readDouble();
-                    // this needs to match the native Interpolator parceling
-                    final int interpolatorType = p.readInt();
-                    final float firstSlope = p.readFloat(); // ignored on the Java side
-                    final float lastSlope = p.readFloat();  // ignored on the Java side
-                    final int length = p.readInt();
-                    final float[] times = new float[length];
-                    final float[] volumes = new float[length];
-                    for (int i = 0; i < length; ++i) {
-                        times[i] = p.readFloat();
-                        volumes[i] = p.readFloat();
-                    }
+        private InterpolatorConfig toInterpolatorParcelable() {
+            InterpolatorConfig parcelable = new InterpolatorConfig();
+            parcelable.type = interpolatorTypeToAidl(mInterpolatorType);
+            parcelable.firstSlope = 0.f; // first slope (specifying for native side)
+            parcelable.lastSlope = 0.f; // last slope (specifying for native side)
+            parcelable.xy = new float[mTimes.length * 2];
+            for (int i = 0; i < mTimes.length; ++i) {
+                parcelable.xy[i * 2] = mTimes[i];
+                parcelable.xy[i * 2 + 1] = mVolumes[i];
+            }
+            return parcelable;
+        }
+
+        /** @hide */
+        public static Configuration fromParcelable(VolumeShaperConfiguration parcelable) {
+            // this needs to match the native VolumeShaper.Configuration parceling
+            final int type = typeFromAidl(parcelable.type);
+            final int id = parcelable.id;
+            if (type == TYPE_ID) {
+                return new VolumeShaper.Configuration(id);
+            } else {
+                final int optionFlags = optionFlagsFromAidl(parcelable.optionFlags);
+                final double durationMs = parcelable.durationMs;
+                final int interpolatorType = interpolatorTypeFromAidl(
+                        parcelable.interpolatorConfig.type);
+                // parcelable.interpolatorConfig.firstSlope is ignored on the Java side
+                // parcelable.interpolatorConfig.lastSlope is ignored on the Java side
+                final int length = parcelable.interpolatorConfig.xy.length;
+                if (length % 2 != 0) {
+                    throw new android.os.BadParcelableException("xy length must be even");
+                }
+                final float[] times = new float[length / 2];
+                final float[] volumes = new float[length / 2];
+                for (int i = 0; i < length / 2; ++i) {
+                    times[i] = parcelable.interpolatorConfig.xy[i * 2];
+                    volumes[i] = parcelable.interpolatorConfig.xy[i * 2 + 1];
+                }
 
-                    return new VolumeShaper.Configuration(
+                return new VolumeShaper.Configuration(
                         type,
                         id,
                         optionFlags,
@@ -533,7 +546,14 @@ public final class VolumeShaper implements AutoCloseable {
                         interpolatorType,
                         times,
                         volumes);
-                }
+            }
+        }
+
+        public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Configuration> CREATOR
+                = new Parcelable.Creator<VolumeShaper.Configuration>() {
+            @Override
+            public VolumeShaper.Configuration createFromParcel(Parcel p) {
+                return fromParcelable(VolumeShaperConfiguration.CREATOR.createFromParcel(p));
             }
 
             @Override
@@ -542,6 +562,84 @@ public final class VolumeShaper implements AutoCloseable {
             }
         };
 
+        private static @InterpolatorType
+        int interpolatorTypeFromAidl(@android.media.InterpolatorType int aidl) {
+            switch (aidl) {
+                case android.media.InterpolatorType.STEP:
+                    return INTERPOLATOR_TYPE_STEP;
+                case android.media.InterpolatorType.LINEAR:
+                    return INTERPOLATOR_TYPE_LINEAR;
+                case android.media.InterpolatorType.CUBIC:
+                    return INTERPOLATOR_TYPE_CUBIC;
+                case android.media.InterpolatorType.CUBIC_MONOTONIC:
+                    return INTERPOLATOR_TYPE_CUBIC_MONOTONIC;
+                default:
+                    throw new BadParcelableException("Unknown interpolator type");
+            }
+        }
+
+        private static @android.media.InterpolatorType
+        int interpolatorTypeToAidl(@InterpolatorType int type) {
+            switch (type) {
+                case INTERPOLATOR_TYPE_STEP:
+                    return android.media.InterpolatorType.STEP;
+                case INTERPOLATOR_TYPE_LINEAR:
+                    return android.media.InterpolatorType.LINEAR;
+                case INTERPOLATOR_TYPE_CUBIC:
+                    return android.media.InterpolatorType.CUBIC;
+                case INTERPOLATOR_TYPE_CUBIC_MONOTONIC:
+                    return android.media.InterpolatorType.CUBIC_MONOTONIC;
+                default:
+                    throw new RuntimeException("Unknown interpolator type");
+            }
+        }
+
+        private static @Type
+        int typeFromAidl(@android.media.VolumeShaperConfigurationType int aidl) {
+            switch (aidl) {
+                case VolumeShaperConfigurationType.ID:
+                    return TYPE_ID;
+                case VolumeShaperConfigurationType.SCALE:
+                    return TYPE_SCALE;
+                default:
+                    throw new BadParcelableException("Unknown type");
+            }
+        }
+
+        private static @android.media.VolumeShaperConfigurationType
+        int typeToAidl(@Type int type) {
+            switch (type) {
+                case TYPE_ID:
+                    return VolumeShaperConfigurationType.ID;
+                case TYPE_SCALE:
+                    return VolumeShaperConfigurationType.SCALE;
+                default:
+                    throw new RuntimeException("Unknown type");
+            }
+        }
+
+        private static int optionFlagsFromAidl(int aidl) {
+            int result = 0;
+            if ((aidl & (1 << VolumeShaperConfigurationOptionFlag.VOLUME_IN_DBFS)) != 0) {
+                result |= OPTION_FLAG_VOLUME_IN_DBFS;
+            }
+            if ((aidl & (1 << VolumeShaperConfigurationOptionFlag.CLOCK_TIME)) != 0) {
+                result |= OPTION_FLAG_CLOCK_TIME;
+            }
+            return result;
+        }
+
+        private static int optionFlagsToAidl(int flags) {
+            int result = 0;
+            if ((flags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
+                result |= (1 << VolumeShaperConfigurationOptionFlag.VOLUME_IN_DBFS);
+            }
+            if ((flags & OPTION_FLAG_CLOCK_TIME) != 0) {
+                result |= (1 << VolumeShaperConfigurationOptionFlag.CLOCK_TIME);
+            }
+            return result;
+        }
+
         /**
          * @hide
          * Constructs a {@code VolumeShaper} from an id.
@@ -1172,25 +1270,31 @@ public final class VolumeShaper implements AutoCloseable {
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            // this needs to match the native VolumeShaper.Operation parceling
-            dest.writeInt(mFlags);
-            dest.writeInt(mReplaceId);
-            dest.writeFloat(mXOffset);
+            toParcelable().writeToParcel(dest, flags);
+        }
+
+        /** @hide */
+        public VolumeShaperOperation toParcelable() {
+            VolumeShaperOperation result = new VolumeShaperOperation();
+            result.flags = flagsToAidl(mFlags);
+            result.replaceId = mReplaceId;
+            result.xOffset = mXOffset;
+            return result;
+        }
+
+        /** @hide */
+        public static Operation fromParcelable(VolumeShaperOperation parcelable) {
+            return new VolumeShaper.Operation(
+                    flagsFromAidl(parcelable.flags),
+                    parcelable.replaceId,
+                    parcelable.xOffset);
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Operation> CREATOR
                 = new Parcelable.Creator<VolumeShaper.Operation>() {
             @Override
             public VolumeShaper.Operation createFromParcel(Parcel p) {
-                // this needs to match the native VolumeShaper.Operation parceling
-                final int flags = p.readInt();
-                final int replaceId = p.readInt();
-                final float xOffset = p.readFloat();
-
-                return new VolumeShaper.Operation(
-                        flags
-                        , replaceId
-                        , xOffset);
+                return fromParcelable(VolumeShaperOperation.CREATOR.createFromParcel(p));
             }
 
             @Override
@@ -1199,6 +1303,46 @@ public final class VolumeShaper implements AutoCloseable {
             }
         };
 
+        private static int flagsFromAidl(int aidl) {
+            int result = 0;
+            if ((aidl & (1 << VolumeShaperOperationFlag.REVERSE)) != 0) {
+                result |= FLAG_REVERSE;
+            }
+            if ((aidl & (1 << VolumeShaperOperationFlag.TERMINATE)) != 0) {
+                result |= FLAG_TERMINATE;
+            }
+            if ((aidl & (1 << VolumeShaperOperationFlag.JOIN)) != 0) {
+                result |= FLAG_JOIN;
+            }
+            if ((aidl & (1 << VolumeShaperOperationFlag.DELAY)) != 0) {
+                result |= FLAG_DEFER;
+            }
+            if ((aidl & (1 << VolumeShaperOperationFlag.CREATE_IF_NECESSARY)) != 0) {
+                result |= FLAG_CREATE_IF_NEEDED;
+            }
+            return result;
+        }
+
+        private static int flagsToAidl(int flags) {
+            int result = 0;
+            if ((flags & FLAG_REVERSE) != 0) {
+                result |= (1 << VolumeShaperOperationFlag.REVERSE);
+            }
+            if ((flags & FLAG_TERMINATE) != 0) {
+                result |= (1 << VolumeShaperOperationFlag.TERMINATE);
+            }
+            if ((flags & FLAG_JOIN) != 0) {
+                result |= (1 << VolumeShaperOperationFlag.JOIN);
+            }
+            if ((flags & FLAG_DEFER) != 0) {
+                result |= (1 << VolumeShaperOperationFlag.DELAY);
+            }
+            if ((flags & FLAG_CREATE_IF_NEEDED) != 0) {
+                result |= (1 << VolumeShaperOperationFlag.CREATE_IF_NECESSARY);
+            }
+            return result;
+        }
+
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         private Operation(@Flag int flags, int replaceId, float xOffset) {
             mFlags = flags;
@@ -1393,17 +1537,27 @@ public final class VolumeShaper implements AutoCloseable {
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeFloat(mVolume);
-            dest.writeFloat(mXOffset);
+            toParcelable().writeToParcel(dest, flags);
+        }
+
+        /** @hide */
+        public VolumeShaperState toParcelable() {
+            VolumeShaperState result = new VolumeShaperState();
+            result.volume = mVolume;
+            result.xOffset = mXOffset;
+            return result;
+        }
+
+        /** @hide */
+        public static State fromParcelable(VolumeShaperState p) {
+            return new VolumeShaper.State(p.volume, p.xOffset);
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.State> CREATOR
                 = new Parcelable.Creator<VolumeShaper.State>() {
             @Override
             public VolumeShaper.State createFromParcel(Parcel p) {
-                return new VolumeShaper.State(
-                        p.readFloat()     // volume
-                        , p.readFloat()); // xOffset
+                return fromParcelable(VolumeShaperState.CREATOR.createFromParcel(p));
             }
 
             @Override